From 71f86d6d23d7b8a46e4c79995802eacd0a0d818d Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 2 Sep 2025 19:46:14 +0200 Subject: [PATCH 1/7] cmake: Enable C++20 Signed-off-by: Philipp Jungkamp --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a798303d..22c5686cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ set(PROJECT_COPYRIGHT "2014-2025 The VILLASframework Authors") # Several CMake settings/defaults set(CMAKE_C_STANDARD 11) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_THREAD_PREFER_PTHREAD ON) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake;${PROJECT_SOURCE_DIR}/common/cmake") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) From e730f56c86d7f1619a342b23c0d55e7dca4eee10 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 2 Sep 2025 19:47:27 +0200 Subject: [PATCH 2/7] fix: Fix libfmt string formatting errors Signed-off-by: Philipp Jungkamp --- common/include/villas/exceptions.hpp | 40 ++++++------------- common/lib/kernel/devices/ip_device.cpp | 2 +- common/lib/kernel/devices/linux_driver.cpp | 5 ++- common/lib/kernel/devices/platform_device.cpp | 6 +-- common/lib/kernel/vfio_container.cpp | 12 +++--- common/lib/table.cpp | 8 ++-- common/lib/utils.cpp | 6 +-- fpga/include/villas/fpga/utils.hpp | 6 +-- include/villas/api.hpp | 34 +++++----------- include/villas/config_class.hpp | 1 - lib/api.cpp | 9 +++-- lib/api/request.cpp | 8 ++-- lib/api/requests/capabiltities.cpp | 5 ++- lib/api/requests/config.cpp | 5 ++- lib/api/requests/graph.cpp | 9 +++-- lib/api/requests/metrics.cpp | 5 ++- lib/api/requests/node.cpp | 7 ++-- lib/api/requests/node_action.cpp | 8 ++-- lib/api/requests/node_file.cpp | 10 +++-- lib/api/requests/node_info.cpp | 5 ++- lib/api/requests/node_stats.cpp | 9 +++-- lib/api/requests/node_stats_reset.cpp | 9 +++-- lib/api/requests/nodes.cpp | 5 ++- lib/api/requests/path.cpp | 7 ++-- lib/api/requests/path_action.cpp | 5 ++- lib/api/requests/path_info.cpp | 5 ++- lib/api/requests/paths.cpp | 5 ++- lib/api/requests/restart.cpp | 13 +++--- lib/api/requests/shutdown.cpp | 5 ++- lib/api/requests/status.cpp | 13 +++--- lib/api/requests/universal.cpp | 4 +- lib/api/requests/universal/channel.cpp | 26 +++++++----- lib/api/requests/universal/channels.cpp | 5 ++- lib/api/requests/universal/info.cpp | 5 ++- lib/api/requests/universal/status.cpp | 5 ++- lib/config.cpp | 10 +++-- lib/nodes/comedi.cpp | 16 ++++---- lib/nodes/infiniband.cpp | 12 +++--- lib/nodes/kafka.cpp | 2 +- lib/nodes/redis.cpp | 2 +- lib/nodes/temper.cpp | 24 ++++++----- lib/super_node.cpp | 1 + 42 files changed, 196 insertions(+), 183 deletions(-) diff --git a/common/include/villas/exceptions.hpp b/common/include/villas/exceptions.hpp index e910dacd2..5d3c960d9 100644 --- a/common/include/villas/exceptions.hpp +++ b/common/include/villas/exceptions.hpp @@ -23,19 +23,17 @@ namespace villas { class SystemError : public std::system_error { public: - SystemError(const std::string &what) - : std::system_error(errno, std::system_category(), what) {} - template - SystemError(const std::string &what, Args &&...args) - : SystemError(fmt::format(what, std::forward(args)...)) {} + SystemError(fmt::format_string what, Args &&...args) + : std::system_error(errno, std::system_category(), + fmt::format(what, std::forward(args)...)) {} }; class RuntimeError : public std::runtime_error { public: template - RuntimeError(const std::string &what, Args &&...args) + RuntimeError(fmt::format_string what, Args &&...args) : std::runtime_error(fmt::format(what, std::forward(args)...)) {} }; @@ -98,17 +96,10 @@ class ConfigError : public std::runtime_error { } template - ConfigError(json_t *s, const std::string &i, - const std::string &what = "Failed to parse configuration") - : std::runtime_error(what), id(i), setting(s) { - error.position = -1; - - msg = strdup(getMessage().c_str()); - } - - template - ConfigError(json_t *s, const std::string &i, const std::string &what, - Args &&...args) + ConfigError( + json_t *s, const std::string &i, + fmt::format_string what = "Failed to parse configuration", + Args &&...args) : std::runtime_error(fmt::format(what, std::forward(args)...)), id(i), setting(s) { error.position = -1; @@ -117,15 +108,10 @@ class ConfigError : public std::runtime_error { } template - ConfigError(json_t *s, const json_error_t &e, const std::string &i, - const std::string &what = "Failed to parse configuration") - : std::runtime_error(what), id(i), setting(s), error(e) { - msg = strdup(getMessage().c_str()); - } - - template - ConfigError(json_t *s, const json_error_t &e, const std::string &i, - const std::string &what, Args &&...args) + ConfigError( + json_t *s, const json_error_t &e, const std::string &i, + fmt::format_string what = "Failed to parse configuration", + Args &&...args) : std::runtime_error(fmt::format(what, std::forward(args)...)), id(i), setting(s), error(e) { msg = strdup(getMessage().c_str()); @@ -137,7 +123,7 @@ class ConfigError : public std::runtime_error { return baseUri + id; } - virtual const char *what() const noexcept { return msg; } + const char *what() const noexcept override { return msg; } }; } // namespace villas diff --git a/common/lib/kernel/devices/ip_device.cpp b/common/lib/kernel/devices/ip_device.cpp index 4f2f2f76d..d5d454978 100644 --- a/common/lib/kernel/devices/ip_device.cpp +++ b/common/lib/kernel/devices/ip_device.cpp @@ -20,7 +20,7 @@ IpDevice IpDevice::from(const fs::path unsafe_path) { if (!is_path_valid(unsafe_path)) throw RuntimeError( "Path {} failed validation as IpDevicePath [adress in hex].[name] ", - unsafe_path.u8string()); + unsafe_path.string()); return IpDevice(unsafe_path); } diff --git a/common/lib/kernel/devices/linux_driver.cpp b/common/lib/kernel/devices/linux_driver.cpp index f9e689868..d6cfcda48 100644 --- a/common/lib/kernel/devices/linux_driver.cpp +++ b/common/lib/kernel/devices/linux_driver.cpp @@ -26,8 +26,9 @@ void LinuxDriver::bind(const Device &device) const { } std::string LinuxDriver::name() const { - size_t pos = path.u8string().rfind('/'); - return path.u8string().substr(pos + 1); + auto string = path.string(); + size_t pos = string.rfind('/'); + return string.substr(pos + 1); } void LinuxDriver::override(const Device &device) const { diff --git a/common/lib/kernel/devices/platform_device.cpp b/common/lib/kernel/devices/platform_device.cpp index 2cf0c6be1..48a98ea70 100644 --- a/common/lib/kernel/devices/platform_device.cpp +++ b/common/lib/kernel/devices/platform_device.cpp @@ -25,12 +25,12 @@ std::optional> PlatformDevice::driver() const { } std::optional PlatformDevice::iommu_group() const { - fs::path symlink = fs::path(this->m_path.u8string() + "/iommu_group"); + fs::path symlink = fs::path(this->m_path.string() + "/iommu_group"); fs::path link = fs::read_symlink(symlink); std::string delimiter = "iommu_groups/"; - int pos = link.u8string().find(delimiter); - int iommu_group = std::stoi(link.u8string().substr(pos + delimiter.length())); + int pos = link.string().find(delimiter); + int iommu_group = std::stoi(link.string().substr(pos + delimiter.length())); return std::make_optional(iommu_group); } diff --git a/common/lib/kernel/vfio_container.cpp b/common/lib/kernel/vfio_container.cpp index 8857a9352..e329443e4 100644 --- a/common/lib/kernel/vfio_container.cpp +++ b/common/lib/kernel/vfio_container.cpp @@ -211,12 +211,12 @@ std::shared_ptr Container::attachDevice(devices::PciDevice &pdev) { } catch (std::exception &e) { throw RuntimeError( - e.what() + - std::string( - "\nBAR of device is in inconsistent state. Rewriting the BAR " - "failed. This can happend due to missing privileges or bad device " - "state. Consider running with root privileges or remove, rescan " - "and reset the device.")); + "{}\n" + "BAR of device is in inconsistent state. Rewriting the BAR \n" + "failed. This can happen due to missing privileges or bad \n" + "device state. Consider running with root privileges or remove, \n" + "rescan and reset the device.\n", + e.what()); } // Get IOMMU group of device diff --git a/common/lib/table.cpp b/common/lib/table.cpp index eb727366f..8152ab96a 100644 --- a/common/lib/table.cpp +++ b/common/lib/table.cpp @@ -116,11 +116,11 @@ void Table::header() { auto &column = columns[i]; auto leftAligned = column.align == TableColumn::Alignment::LEFT; - line1 += fmt::format(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}") - : CLR_BLD(" {0:>{1}.{1}s}"), + line1 += fmt::format(fmt::runtime(leftAligned ? CLR_BLD(" {0:<{1}.{1}s}") + : CLR_BLD(" {0:>{1}.{1}s}")), column.title, column._width); - line2 += fmt::format(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}") - : CLR_YEL(" {0:>{1}.{1}s}"), + line2 += fmt::format(fmt::runtime(leftAligned ? CLR_YEL(" {0:<{1}.{1}s}") + : CLR_YEL(" {0:>{1}.{1}s}")), column.unit, column._width); for (int j = 0; j < column._width + 2; j++) { diff --git a/common/lib/utils.cpp b/common/lib/utils.cpp index 33195b357..1431533eb 100644 --- a/common/lib/utils.cpp +++ b/common/lib/utils.cpp @@ -9,12 +9,10 @@ #include #include #include -#include #include #include #include #include -#include #include #include @@ -355,8 +353,8 @@ bool isPrivileged() { } void write_to_file(std::string data, const fs::path file) { - villas::Log::get("Filewriter")->debug("{} > {}", data, file.u8string()); - std::ofstream outputFile(file.u8string()); + villas::Log::get("Filewriter")->debug("{} > {}", data, file.string()); + std::ofstream outputFile(file.string()); if (outputFile.is_open()) { outputFile << data; diff --git a/fpga/include/villas/fpga/utils.hpp b/fpga/include/villas/fpga/utils.hpp index 97a0a6807..d8493063c 100644 --- a/fpga/include/villas/fpga/utils.hpp +++ b/fpga/include/villas/fpga/utils.hpp @@ -105,9 +105,9 @@ class BufferedSampleFormatterShort : public BufferedSampleFormatter { size_t chars; if ((chars = std::snprintf(nextBufPos(), formatStringSize + 1, formatString, value)) > (int)formatStringSize) { - throw RuntimeError("Output buffer too small. Expected " + - std::to_string(formatStringSize) + - " characters, got " + std::to_string(chars)); + throw RuntimeError( + "Output buffer too small. Expected {} characters, got {}", + formatStringSize, chars); } } diff --git a/include/villas/api.hpp b/include/villas/api.hpp index b4a682865..bf99ad1a6 100644 --- a/include/villas/api.hpp +++ b/include/villas/api.hpp @@ -34,36 +34,24 @@ class Error : public RuntimeError { public: template - Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, - const std::string &msg = "Invalid API request", Args &&...args) - : RuntimeError(msg, std::forward(args)...), code(c), json(nullptr) { - } + Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, json_t *json = nullptr, + fmt::format_string what = "Invalid API request", + Args &&...args) + : RuntimeError(what, std::forward(args)...), code(c), json(json) {} template - Error(int c = HTTP_STATUS_INTERNAL_SERVER_ERROR, - const std::string &msg = "Invalid API request", - const char *fmt = nullptr, Args &&...args) - : RuntimeError(msg), code(c), - json(fmt ? json_pack(fmt, std::forward(args)...) : nullptr) {} + static Error badRequest(json_t *json = nullptr, + fmt::format_string what = "Bad API request", + Args &&...args) { + return {HTTP_STATUS_BAD_REQUEST, json, what, std::forward(args)...}; + } + + static Error invalidMethod(Request *req); int code; json_t *json; }; -class BadRequest : public Error { - -public: - template - BadRequest(const std::string &msg = "Bad API request", Args &&...args) - : Error(HTTP_STATUS_BAD_REQUEST, msg, std::forward(args)...) {} -}; - -class InvalidMethod : public BadRequest { - -public: - InvalidMethod(Request *req); -}; - } // namespace api // Forward declarations diff --git a/include/villas/config_class.hpp b/include/villas/config_class.hpp index 9b9458676..e6b372b9c 100644 --- a/include/villas/config_class.hpp +++ b/include/villas/config_class.hpp @@ -9,7 +9,6 @@ #include #include -#include #include #include diff --git a/lib/api.cpp b/lib/api.cpp index ac7c92942..0a1ed1a14 100644 --- a/lib/api.cpp +++ b/lib/api.cpp @@ -18,10 +18,11 @@ using namespace villas; using namespace villas::node; using namespace villas::node::api; -InvalidMethod::InvalidMethod(Request *req) - : BadRequest("The '{}' API endpoint does not support {} requests", - req->factory->getName(), - Session::methodToString(req->method)) {} +Error Error::invalidMethod(Request *req) { + return badRequest( + nullptr, "The '{}' API endpoint does not support {} requests", + req->factory->getName(), Session::methodToString(req->method)); +} Api::Api(SuperNode *sn) : logger(Log::get("api")), state(State::INITIALIZED), super_node(sn) {} diff --git a/lib/api/request.cpp b/lib/api/request.cpp index e8e508ada..7d19e8762 100644 --- a/lib/api/request.cpp +++ b/lib/api/request.cpp @@ -15,7 +15,7 @@ using namespace villas::node::api; void Request::decode() { body = buffer.decode(); if (!body) - throw BadRequest("Failed to decode request payload"); + throw Error::badRequest(nullptr, "Failed to decode request payload"); } std::string Request::toString() { @@ -46,6 +46,8 @@ Request *RequestFactory::create(Session *s, const std::string &uri, return p; } - throw BadRequest("Unknown API request", "{ s: s, s: s }", "uri", uri.c_str(), - "method", Session::methodToString(meth).c_str()); + throw Error::badRequest(json_pack("{ s: s, s: s }", "uri", uri.c_str(), + "method", + Session::methodToString(meth).c_str()), + "Unknown API request"); } diff --git a/lib/api/requests/capabiltities.cpp b/lib/api/requests/capabiltities.cpp index cda9b0f86..6a7861862 100644 --- a/lib/api/requests/capabiltities.cpp +++ b/lib/api/requests/capabiltities.cpp @@ -20,10 +20,11 @@ class CapabilitiesRequest : public Request { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Capabilities endpoint does not accept any body data"); + throw Error::badRequest( + nullptr, "Capabilities endpoint does not accept any body data"); auto *json_capabilities = getCapabilities(); diff --git a/lib/api/requests/config.cpp b/lib/api/requests/config.cpp index 73da4fc8e..2332f35b9 100644 --- a/lib/api/requests/config.cpp +++ b/lib/api/requests/config.cpp @@ -23,10 +23,11 @@ class ConfigRequest : public Request { json_t *json = session->getSuperNode()->getConfig(); if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Config endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Config endpoint does not accept any body data"); auto *json_config = json ? json_incref(json) : json_object(); diff --git a/lib/api/requests/graph.cpp b/lib/api/requests/graph.cpp index 2d5ed0d6e..5b113223e 100644 --- a/lib/api/requests/graph.cpp +++ b/lib/api/requests/graph.cpp @@ -36,10 +36,11 @@ class GraphRequest : public Request { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Status endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Status endpoint does not accept any body data"); auto *sn = session->getSuperNode(); auto *graph = sn->getGraph(); @@ -59,12 +60,12 @@ class GraphRequest : public Request { auto lit = std::find(supportedLayouts.begin(), supportedLayouts.end(), layout); if (lit == supportedLayouts.end()) - throw BadRequest("Unsupported layout: {}", layout); + throw Error::badRequest(nullptr, "Unsupported layout: {}", layout); auto fit = std::find(supportedFormats.begin(), supportedFormats.end(), format); if (fit == supportedFormats.end()) - throw BadRequest("Unsupported format: {}", format); + throw Error::badRequest(nullptr, "Unsupported format: {}", format); std::string ct = "text/plain"; if (format == "svg") diff --git a/lib/api/requests/metrics.cpp b/lib/api/requests/metrics.cpp index 689e9ab74..08d7c9c32 100644 --- a/lib/api/requests/metrics.cpp +++ b/lib/api/requests/metrics.cpp @@ -28,11 +28,12 @@ class MetricsRequest : public Request { virtual Response *execute() { if (method != Session::Method::GET) { - throw InvalidMethod(this); + throw Error::invalidMethod(this); } if (body != nullptr) { - throw BadRequest("The metrics endpoint does not accept any body data"); + throw Error::badRequest( + nullptr, "The metrics endpoint does not accept any body data"); } std::stringstream ss; diff --git a/lib/api/requests/node.cpp b/lib/api/requests/node.cpp index b66f869ce..89fab17f9 100644 --- a/lib/api/requests/node.cpp +++ b/lib/api/requests/node.cpp @@ -19,11 +19,12 @@ void NodeRequest::prepare() { if (ret) { node = nodes.lookup(matches[1]); if (!node) - throw BadRequest("Unknown node", "{ s: s }", "node", matches[1].c_str()); + throw Error::badRequest(json_pack("{ s: s }", "node", matches[1].c_str()), + "Unknown node"); } else { node = nodes.lookup(uuid); if (!node) - throw BadRequest("No node found with with matching UUID", "{ s: s }", - "uuid", matches[1].c_str()); + throw Error::badRequest(json_pack("{ s: s }", "uuid", matches[1].c_str()), + "No node found with with matching UUID"); } } diff --git a/lib/api/requests/node_action.cpp b/lib/api/requests/node_action.cpp index df66a9ff2..be549fe45 100644 --- a/lib/api/requests/node_action.cpp +++ b/lib/api/requests/node_action.cpp @@ -26,14 +26,16 @@ template class NodeActionRequest : public NodeRequest { Response *execute() override { if (method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Node endpoints do not accept any body data"); + throw Error::badRequest(nullptr, + "Node endpoints do not accept any body data"); int ret = (node->*func)(); if (ret) - throw BadRequest("Failed to execute action", "{ s: d }", "ret", ret); + throw Error::badRequest(nullptr, "Failed to execute action", "{ s: d }", + "ret", ret); return new Response(session, HTTP_STATUS_OK); } diff --git a/lib/api/requests/node_file.cpp b/lib/api/requests/node_file.cpp index 436cd84d1..5b5dbf333 100644 --- a/lib/api/requests/node_file.cpp +++ b/lib/api/requests/node_file.cpp @@ -24,16 +24,18 @@ class FileRequest : public NodeRequest { Response *execute() override { if (method != Session::Method::GET && method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("File endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "File endpoint does not accept any body data"); NodeFactory *nf = plugin::registry->lookup("file"); if (node->getFactory() != nf) - throw BadRequest("This node is not a file node", "{ s: s }", "type", - node->getFactory()->getName()); + throw Error::badRequest(nullptr, "This node is not a file node", + "{ s: s }", "type", + node->getFactory()->getName()); auto *nc = dynamic_cast(node); auto *f = nc->getData(); diff --git a/lib/api/requests/node_info.cpp b/lib/api/requests/node_info.cpp index 5e08188e8..255031626 100644 --- a/lib/api/requests/node_info.cpp +++ b/lib/api/requests/node_info.cpp @@ -26,10 +26,11 @@ class NodeInfoRequest : public NodeRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Nodes endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Nodes endpoint does not accept any body data"); auto *json_node = node->toJson(); diff --git a/lib/api/requests/node_stats.cpp b/lib/api/requests/node_stats.cpp index 5d72f77c1..c1a22ee48 100644 --- a/lib/api/requests/node_stats.cpp +++ b/lib/api/requests/node_stats.cpp @@ -27,14 +27,15 @@ class StatsRequest : public NodeRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Stats endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Stats endpoint does not accept any body data"); if (node->getStats() == nullptr) - throw BadRequest( - "The statistics collection for this node is not enabled"); + throw Error::badRequest( + nullptr, "The statistics collection for this node is not enabled"); return new JsonResponse(session, HTTP_STATUS_OK, node->getStats()->toJson()); diff --git a/lib/api/requests/node_stats_reset.cpp b/lib/api/requests/node_stats_reset.cpp index c162893d6..cb3f0cbfd 100644 --- a/lib/api/requests/node_stats_reset.cpp +++ b/lib/api/requests/node_stats_reset.cpp @@ -27,14 +27,15 @@ class StatsRequest : public NodeRequest { Response *execute() override { if (method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Stats endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Stats endpoint does not accept any body data"); if (node->getStats() == nullptr) - throw BadRequest( - "The statistics collection for this node is not enabled"); + throw Error::badRequest( + nullptr, "The statistics collection for this node is not enabled"); node->getStats()->reset(); diff --git a/lib/api/requests/nodes.cpp b/lib/api/requests/nodes.cpp index 1b8711081..f53ab432a 100644 --- a/lib/api/requests/nodes.cpp +++ b/lib/api/requests/nodes.cpp @@ -26,10 +26,11 @@ class NodesRequest : public Request { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Nodes endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Nodes endpoint does not accept any body data"); json_t *json_nodes = session->getSuperNode()->getNodes().toJson(); diff --git a/lib/api/requests/path.cpp b/lib/api/requests/path.cpp index aae5cddb4..b3ed3c5d1 100644 --- a/lib/api/requests/path.cpp +++ b/lib/api/requests/path.cpp @@ -16,11 +16,12 @@ void PathRequest::prepare() { ret = uuid_parse(matches[1].c_str(), uuid); if (ret) - throw BadRequest("Invalid UUID", "{ s: s }", "uuid", matches[1].c_str()); + throw Error::badRequest(json_pack("{ s: s }", "uuid", matches[1].c_str()), + "Invalid UUID"); auto paths = session->getSuperNode()->getPaths(); path = paths.lookup(uuid); if (!path) - throw BadRequest("No path found with with matching UUID", "{ s: s }", - "uuid", matches[1].c_str()); + throw Error::badRequest(json_pack("{ s: s }", "uuid", matches[1].c_str()), + "No path found with with matching UUID"); } diff --git a/lib/api/requests/path_action.cpp b/lib/api/requests/path_action.cpp index e1c5be29e..efc943487 100644 --- a/lib/api/requests/path_action.cpp +++ b/lib/api/requests/path_action.cpp @@ -26,10 +26,11 @@ template class PathActionRequest : public PathRequest { Response *execute() override { if (method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Path endpoints do not accept any body data"); + throw Error::badRequest(nullptr, + "Path endpoints do not accept any body data"); (path->*func)(); diff --git a/lib/api/requests/path_info.cpp b/lib/api/requests/path_info.cpp index a17a3ca37..1f1e18cfb 100644 --- a/lib/api/requests/path_info.cpp +++ b/lib/api/requests/path_info.cpp @@ -26,10 +26,11 @@ class PathInfoRequest : public PathRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Endpoint does not accept any body data"); return new JsonResponse(session, HTTP_STATUS_OK, path->toJson()); } diff --git a/lib/api/requests/paths.cpp b/lib/api/requests/paths.cpp index 54915466b..ae0ccbd16 100644 --- a/lib/api/requests/paths.cpp +++ b/lib/api/requests/paths.cpp @@ -26,10 +26,11 @@ class PathsRequest : public Request { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Paths endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Paths endpoint does not accept any body data"); json_t *json_paths = session->getSuperNode()->getPaths().toJson(); diff --git a/lib/api/requests/restart.cpp b/lib/api/requests/restart.cpp index 968d42f2b..08b11966d 100644 --- a/lib/api/requests/restart.cpp +++ b/lib/api/requests/restart.cpp @@ -48,14 +48,14 @@ class RestartRequest : public Request { json_error_t err; if (method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); json_t *json_config = nullptr; if (body) { ret = json_unpack_ex(body, &err, 0, "{ s?: o }", "config", &json_config); if (ret < 0) - throw BadRequest("Failed to parse request body"); + throw Error::badRequest(nullptr, "Failed to parse request body"); } if (json_config) { @@ -69,14 +69,15 @@ class RestartRequest : public Request { ret = json_dumpf(json_config, configFile, JSON_INDENT(4)); if (ret < 0) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to create temporary config file"); fclose(configFile); configUri = configUriBuf; } else if (json_config != nullptr) - throw BadRequest("Parameter 'config' must be either a URL (string) or " - "a configuration (object)"); + throw Error::badRequest( + nullptr, "Parameter 'config' must be either a URL (string) or " + "a configuration (object)"); } else // If no config is provided via request, we will use the previous one configUri = session->getSuperNode()->getConfigPath(); @@ -98,7 +99,7 @@ class RestartRequest : public Request { // Register exit handler ret = atexit(handler); if (ret) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to restart VILLASnode instance"); // Properly terminate current instance diff --git a/lib/api/requests/shutdown.cpp b/lib/api/requests/shutdown.cpp index ddc57211a..8bd5fd1a6 100644 --- a/lib/api/requests/shutdown.cpp +++ b/lib/api/requests/shutdown.cpp @@ -22,10 +22,11 @@ class ShutdownRequest : public Request { Response *execute() override { if (method != Session::Method::POST) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Shutdown endpoint does not accept any body data"); + throw Error::badRequest( + nullptr, "Shutdown endpoint does not accept any body data"); utils::killme(SIGTERM); diff --git a/lib/api/requests/status.cpp b/lib/api/requests/status.cpp index 3189f19b7..f0d1c6a90 100644 --- a/lib/api/requests/status.cpp +++ b/lib/api/requests/status.cpp @@ -27,10 +27,11 @@ class StatusRequest : public Request { int ret; if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("Status endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "Status endpoint does not accept any body data"); auto *sn = session->getSuperNode(); @@ -43,17 +44,17 @@ class StatusRequest : public Request { ret = gethostname(hname, sizeof(hname)); if (ret) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to get system hostname"); ret = uname(&uts); if (ret) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to get kernel information"); ret = sysinfo(&sinfo); if (ret) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to get system information"); float f_load = 1.f / (1 << SI_LOAD_SHIFT); @@ -118,7 +119,7 @@ class StatusRequest : public Request { "total", (json_int_t)(sinfo.totalhigh * sinfo.mem_unit), // "free", (json_int_t)(sinfo.freehigh * sinfo.mem_unit)); if (!json_status) - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, "Failed to prepare response: {}", err.text); return new JsonResponse(session, HTTP_STATUS_OK, json_status); diff --git a/lib/api/requests/universal.cpp b/lib/api/requests/universal.cpp index d3083cef5..f4ffee732 100644 --- a/lib/api/requests/universal.cpp +++ b/lib/api/requests/universal.cpp @@ -16,6 +16,6 @@ void UniversalRequest::prepare() { api_node = dynamic_cast(node); if (!api_node) - throw BadRequest("Node {} is not an univeral API node!", - node->getNameShort()); + throw Error::badRequest(nullptr, "Node {} is not an univeral API node!", + node->getNameShort()); } diff --git a/lib/api/requests/universal/channel.cpp b/lib/api/requests/universal/channel.cpp index 5efd4b985..df543acbc 100644 --- a/lib/api/requests/universal/channel.cpp +++ b/lib/api/requests/universal/channel.cpp @@ -20,27 +20,29 @@ class ChannelRequest : public UniversalRequest { Response *executeGet(const std::string &signalName, PayloadType payload) { if (body != nullptr) - throw BadRequest("This endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "This endpoint does not accept any body data"); pthread_mutex_lock(&api_node->write.mutex); auto *smp = api_node->write.sample; if (!smp) { pthread_mutex_unlock(&api_node->write.mutex); - throw Error(HTTP_STATUS_NOT_FOUND, "No data available"); + throw Error(HTTP_STATUS_NOT_FOUND, nullptr, "No data available"); } auto idx = smp->signals->getIndexByName(signalName); if (idx < 0) { pthread_mutex_unlock(&api_node->write.mutex); - throw Error(HTTP_STATUS_NOT_FOUND, "Unknown signal id: {}", signalName); + throw Error(HTTP_STATUS_NOT_FOUND, nullptr, "Unknown signal id: {}", + signalName); } auto sig = smp->signals->getByIndex(idx); auto ch = api_node->write.channels.at(idx); if (payload != ch->payload) - throw BadRequest("Mismatching payload type"); + throw Error::badRequest(nullptr, "Mismatching payload type"); auto *json_signal = json_pack("{ s: f, s: o, s: s, s: s, s: s }", "timestamp", @@ -66,20 +68,21 @@ class ChannelRequest : public UniversalRequest { auto *smp = api_node->read.sample; if (!smp) { pthread_mutex_unlock(&api_node->read.mutex); - throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, "Not initialized yet"); + throw Error(HTTP_STATUS_INTERNAL_SERVER_ERROR, nullptr, + "Not initialized yet"); } auto idx = smp->signals->getIndexByName(signalName); if (idx < 0) { pthread_mutex_unlock(&api_node->read.mutex); - throw BadRequest("Unknown signal id: {}", signalName); + throw Error::badRequest(nullptr, "Unknown signal id: {}", signalName); } auto sig = smp->signals->getByIndex(idx); auto ch = api_node->read.channels.at(idx); if (payload != ch->payload) - throw BadRequest("Mismatching payload type"); + throw Error::badRequest(nullptr, "Mismatching payload type"); double timestamp = 0; json_t *json_value; @@ -94,7 +97,7 @@ class ChannelRequest : public UniversalRequest { "source", &source); if (ret) { pthread_mutex_unlock(&api_node->read.mutex); - throw BadRequest("Malformed body: {}", err.text); + throw Error::badRequest(nullptr, "Malformed body: {}", err.text); } if (validity) @@ -109,7 +112,7 @@ class ChannelRequest : public UniversalRequest { ret = smp->data[idx].parseJson(sig->type, json_value); if (ret) { pthread_mutex_unlock(&api_node->read.mutex); - throw BadRequest("Malformed value"); + throw Error::badRequest(nullptr, "Malformed value"); } smp->ts.origin = time_from_double(timestamp); @@ -130,7 +133,8 @@ class ChannelRequest : public UniversalRequest { else if (subResource == "sample") payload = PayloadType::EVENTS; else - throw BadRequest("Unsupported sub-resource: {}", subResource); + throw Error::badRequest(nullptr, "Unsupported sub-resource: {}", + subResource); switch (method) { case Session::Method::GET: @@ -138,7 +142,7 @@ class ChannelRequest : public UniversalRequest { case Session::Method::PUT: return executePut(signalName, payload); default: - throw InvalidMethod(this); + throw Error::invalidMethod(this); } } }; diff --git a/lib/api/requests/universal/channels.cpp b/lib/api/requests/universal/channels.cpp index 420add303..62ff6fbc9 100644 --- a/lib/api/requests/universal/channels.cpp +++ b/lib/api/requests/universal/channels.cpp @@ -20,10 +20,11 @@ class SignalsRequest : public UniversalRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("This endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "This endpoint does not accept any body data"); auto *json_sigs = json_array(); diff --git a/lib/api/requests/universal/info.cpp b/lib/api/requests/universal/info.cpp index 976cbae19..fa8219c81 100644 --- a/lib/api/requests/universal/info.cpp +++ b/lib/api/requests/universal/info.cpp @@ -21,10 +21,11 @@ class InfoRequest : public UniversalRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("This endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "This endpoint does not accept any body data"); auto *info = json_pack("{ s: s, s: s, s: { s: s, s: s } }", // "id", node->getNameShort().c_str(), // diff --git a/lib/api/requests/universal/status.cpp b/lib/api/requests/universal/status.cpp index 4db6e480a..47fd5c152 100644 --- a/lib/api/requests/universal/status.cpp +++ b/lib/api/requests/universal/status.cpp @@ -20,10 +20,11 @@ class StatusRequest : public UniversalRequest { Response *execute() override { if (method != Session::Method::GET) - throw InvalidMethod(this); + throw Error::invalidMethod(this); if (body != nullptr) - throw BadRequest("This endpoint does not accept any body data"); + throw Error::badRequest(nullptr, + "This endpoint does not accept any body data"); auto *json_response = json_pack("{ s: s }", diff --git a/lib/config.cpp b/lib/config.cpp index 0bd9cc190..dd149914e 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include @@ -338,7 +339,8 @@ json_t *Config::expandIncludes(json_t *in) { for (auto &path : resolveIncludes(pattern)) { json_t *other = load(path); if (!other) - throw ConfigError(str, "Failed to include config file from {}", path); + throw ConfigError(str, "include", + "Failed to include config file from {}", path); if (!incl) incl = other; @@ -346,12 +348,14 @@ json_t *Config::expandIncludes(json_t *in) { ret = json_object_update_recursive(incl, other); if (ret) throw ConfigError( - str, "Can not mix object and array-typed include files"); + str, "include", + "Can not mix object and array-typed include files"); } else if (json_is_array(incl) && json_is_array(other)) { ret = json_array_extend(incl, other); if (ret) throw ConfigError( - str, "Can not mix object and array-typed include files"); + str, "include", + "Can not mix object and array-typed include files"); } logger->debug("Included config from: {}", path); diff --git a/lib/nodes/comedi.cpp b/lib/nodes/comedi.cpp index 4842021e2..f37898a96 100644 --- a/lib/nodes/comedi.cpp +++ b/lib/nodes/comedi.cpp @@ -157,7 +157,8 @@ static int comedi_start_in(NodeCompat *n) { if (d->subdevice < 0) { d->subdevice = comedi_find_subdevice_by_type(c->dev, COMEDI_SUBD_AI, 0); if (d->subdevice < 0) - throw RuntimeError("Cannot find analog input device for node '{}'"); + throw RuntimeError("Cannot find analog input device for node '{}'", + n->getNameShort()); } else { // Check if subdevice is usable ret = comedi_get_subdevice_type(c->dev, d->subdevice); @@ -305,7 +306,8 @@ static int comedi_start_out(NodeCompat *n) { ret = comedi_command(c->dev, &cmd); if (ret < 0) throw RuntimeError( - "Failed to issue command to input subdevice of node '{}'"); + "Failed to issue command to input subdevice of node '{}'", + n->getNameShort()); // Output will only start after the internal trigger d->running = false; @@ -966,19 +968,19 @@ static void comedi_dump_cmd(Logger logger, comedi_cmd *cmd) { logger->debug("subdevice: {}", cmd->subdev); src = comedi_cmd_trigger_src(cmd->start_src, buf); - logger->debug("start: {:-8s} {}", src, cmd->start_arg); + logger->debug("start: {:8s} {}", src, cmd->start_arg); src = comedi_cmd_trigger_src(cmd->scan_begin_src, buf); - logger->debug("scan_begin: {:-8s} {}", src, cmd->scan_begin_arg); + logger->debug("scan_begin: {:8s} {}", src, cmd->scan_begin_arg); src = comedi_cmd_trigger_src(cmd->convert_src, buf); - logger->debug("convert: {:-8s} {}", src, cmd->convert_arg); + logger->debug("convert: {:8s} {}", src, cmd->convert_arg); src = comedi_cmd_trigger_src(cmd->scan_end_src, buf); - logger->debug("scan_end: {:-8s} {}", src, cmd->scan_end_arg); + logger->debug("scan_end: {:8s} {}", src, cmd->scan_end_arg); src = comedi_cmd_trigger_src(cmd->stop_src, buf); - logger->debug("stop: {:-8s} {}", src, cmd->stop_arg); + logger->debug("stop: {:8s} {}", src, cmd->stop_arg); } int villas::node::comedi_poll_fds(NodeCompat *n, int fds[]) { diff --git a/lib/nodes/infiniband.cpp b/lib/nodes/infiniband.cpp index 03c66dcb9..46adcb483 100644 --- a/lib/nodes/infiniband.cpp +++ b/lib/nodes/infiniband.cpp @@ -447,10 +447,12 @@ static void ib_continue_as_listen(NodeCompat *n, struct rdma_cm_event *event) { if (ib->conn.use_fallback) n->logger->warn("Trying to continue as listening node"); else - throw RuntimeError("Cannot establish a connection with remote host! If you " - "want that {} tries to " - "continue as listening node in such cases, set " - "use_fallback = true in the configuration"); + throw RuntimeError( + "Cannot establish a connection with remote host! If you \n" + "want that {} tries to \n" + "continue as listening node in such cases, set \n" + "use_fallback = true in the configuration\n", + n->getNameShort()); n->setState(State::STARTED); @@ -961,7 +963,7 @@ int villas::node::ib_write(NodeCompat *n, struct Sample *const smps[], * and prepare them to be released */ n->logger->debug( - "Bad WR occured with ID: {:#x} and S/G address: {:#x}: {}", + "Bad WR occured with ID: {:#x} and S/G address: {:p}: {}", bad_wr->wr_id, (void *)bad_wr->sg_list, ret); while (1) { diff --git a/lib/nodes/kafka.cpp b/lib/nodes/kafka.cpp index 183717d27..1c56e1e5f 100644 --- a/lib/nodes/kafka.cpp +++ b/lib/nodes/kafka.cpp @@ -434,7 +434,7 @@ int villas::node::kafka_start(NodeCompat *n) { kafka_config_error: rd_kafka_conf_destroy(rdkconf); - throw RuntimeError(errstr); + throw RuntimeError("{}", errstr); return -1; } diff --git a/lib/nodes/redis.cpp b/lib/nodes/redis.cpp index ee9f3eb60..0faa454cb 100644 --- a/lib/nodes/redis.cpp +++ b/lib/nodes/redis.cpp @@ -60,7 +60,7 @@ RedisConnection::get(const sw::redis::ConnectionOptions &opts) { try { conn = new RedisConnection(opts); } catch (sw::redis::IoError &e) { - throw RuntimeError(e.what()); + throw RuntimeError("{}", e.what()); } connections[opts] = conn; diff --git a/lib/nodes/temper.cpp b/lib/nodes/temper.cpp index 53289c8ab..9849657e7 100644 --- a/lib/nodes/temper.cpp +++ b/lib/nodes/temper.cpp @@ -240,8 +240,8 @@ int villas::node::temper_type_start(villas::node::SuperNode *sn) { auto *dev = TEMPerDevice::make(devs[i]); logger->debug( - "Found Temper device at bus={03d}, port={03d}, vendor_id={04x}, " - "product_id={04x}, manufacturer={}, product={}, serial={}", + "Found Temper device at bus={:03d}, port={:03d}, vendor_id={:04x}, " + "product_id={:04x}, manufacturer={}, product={}, serial={}", dev->getBus(), dev->getPort(), dev->getDescriptor().idVendor, dev->getDescriptor().idProduct, dev->getManufacturer(), dev->getProduct(), dev->getSerial()); @@ -305,15 +305,17 @@ int villas::node::temper_parse(NodeCompat *n, json_t *json) { char *villas::node::temper_print(NodeCompat *n) { auto *t = n->getData(); - return strf("product=%s, manufacturer=%s, serial=%s humidity=%s, " - "temperature=%d, usb.vendor_id=%#x, usb.product_id=%#x, " - "calibration.scale=%f, calibration.offset=%f", - t->device->getProduct(), t->device->getManufacturer(), - t->device->getSerial(), - t->device->hasHumiditySensor() ? "yes" : "no", - t->device->getNumSensors(), t->device->getDescriptor().idVendor, - t->device->getDescriptor().idProduct, t->calibration.scale, - t->calibration.offset); + return strdup( + fmt::format( + "product={}, manufacturer={}, serial={}, humidity={}, " + "temperature={}, usb.vendor_id={:04x}, usb.product_id={:04x}, " + "calibration.scale={}, calibration.offset={}", + t->device->getProduct(), t->device->getManufacturer(), + t->device->getSerial(), t->device->hasHumiditySensor() ? "yes" : "no", + t->device->getNumSensors(), t->device->getDescriptor().idVendor, + t->device->getDescriptor().idProduct, t->calibration.scale, + t->calibration.offset) + .c_str()); } int villas::node::temper_prepare(NodeCompat *n) { diff --git a/lib/super_node.cpp b/lib/super_node.cpp index 3f91f2588..00fd8e8f8 100644 --- a/lib/super_node.cpp +++ b/lib/super_node.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include From a2ede5243dc9e2364d13ee4264c0511a5468fe18 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 2 Sep 2025 21:39:41 +0200 Subject: [PATCH 3/7] fix(deps): Update criterion installed by deps.sh Signed-off-by: Philipp Jungkamp --- packaging/deps.sh | 69 ++++++++++++++++-------------- packaging/docker/Dockerfile.debian | 7 +-- packaging/docker/Dockerfile.fedora | 2 +- packaging/docker/Dockerfile.rocky | 4 +- packaging/docker/Dockerfile.ubuntu | 6 +-- 5 files changed, 46 insertions(+), 42 deletions(-) diff --git a/packaging/deps.sh b/packaging/deps.sh index 73103654d..a4ca74202 100644 --- a/packaging/deps.sh +++ b/packaging/deps.sh @@ -101,15 +101,39 @@ TMPDIR=$(mktemp -d) echo "Entering ${TMPDIR}" pushd ${TMPDIR} >/dev/null +# Enter python venv +python3 -m venv venv +. venv/bin/activate +python3 -m pip install --upgrade pip setuptools + +# Install meson +if ! command -v meson; then + # Note: meson 0.61.5 is the latest version which supports the CMake version on the target + pip3 install meson==0.61.5 +fi + +# Install ninja +if ! command -v ninja; then + curl -L https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-linux.zip > ninja-linux.zip + unzip ninja-linux.zip + export PATH=${PATH}:. +fi + # Build & Install Criterion if ! pkg-config "criterion >= 2.4.1" && \ [ "${ARCH}" == "x86_64" ] && \ should_build "criterion" "for unit tests"; then - git clone ${GIT_OPTS} --branch v2.3.3 --recursive https://github.com/Snaipe/Criterion.git - mkdir -p Criterion/build - pushd Criterion/build - cmake ${CMAKE_OPTS} .. - make ${MAKE_OPTS} install + git clone ${GIT_OPTS} --branch v2.4.2 --recursive https://github.com/Snaipe/Criterion.git + pushd Criterion + + meson setup \ + --prefix=${PREFIX} \ + --cmake-prefix-path=${PREFIX} \ + --backend=ninja \ + build + meson compile -C build + meson install -C build + popd fi @@ -426,34 +450,13 @@ if ! pkg-config "nice >= 0.1.16" && \ mkdir -p libnice/build pushd libnice - # Create sub-shell to constrain meson venv and ninja PATH to this build - ( - # Install meson - if ! command -v meson; then - python3 -m venv venv - . venv/bin/activate - python3 -m pip install --upgrade pip setuptools - - - # Note: meson 0.61.5 is the latest version which supports the CMake version on the target - pip3 install meson==0.61.5 - fi - - # Install ninja - if ! command -v ninja; then - curl -L https://github.com/ninja-build/ninja/releases/download/v1.11.1/ninja-linux.zip > ninja-linux.zip - unzip ninja-linux.zip - export PATH=${PATH}:. - fi - - meson setup \ - --prefix=${PREFIX} \ - --cmake-prefix-path=${PREFIX} \ - --backend=ninja \ - build - meson compile -C build - meson install -C build - ) + meson setup \ + --prefix=${PREFIX} \ + --cmake-prefix-path=${PREFIX} \ + --backend=ninja \ + build + meson compile -C build + meson install -C build popd fi diff --git a/packaging/docker/Dockerfile.debian b/packaging/docker/Dockerfile.debian index 7101c95f9..b6e2024b9 100644 --- a/packaging/docker/Dockerfile.debian +++ b/packaging/docker/Dockerfile.debian @@ -18,12 +18,13 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get install -y \ gcc g++ \ - pkg-config cmake make \ - autoconf automake autogen libtool \ + pkg-config cmake make meson \ + autoconf automake autogen libtool ninja-build \ texinfo git git-svn curl tar wget diffutils \ flex bison \ protobuf-compiler protobuf-c-compiler \ - clang-format clangd + clang-format clangd \ + python3-venv unzip # Dependencies RUN apt-get update && \ diff --git a/packaging/docker/Dockerfile.fedora b/packaging/docker/Dockerfile.fedora index e8799d158..3c3b955ab 100644 --- a/packaging/docker/Dockerfile.fedora +++ b/packaging/docker/Dockerfile.fedora @@ -15,7 +15,7 @@ ARG DISTRO # Toolchain RUN dnf -y install \ gcc-14 g++-14 \ - pkgconfig cmake make \ + pkgconfig cmake make meson ninja \ autoconf automake autogen libtool \ texinfo git awk git-svn curl tar patchutils \ flex bison \ diff --git a/packaging/docker/Dockerfile.rocky b/packaging/docker/Dockerfile.rocky index ce80356ce..b84c014df 100644 --- a/packaging/docker/Dockerfile.rocky +++ b/packaging/docker/Dockerfile.rocky @@ -20,8 +20,8 @@ RUN dnf config-manager --set-enabled crb # Toolchain RUN dnf --allowerasing -y install \ gcc gcc-c++ \ - pkgconfig cmake make \ - autoconf automake libtool \ + pkgconfig cmake make meson \ + autoconf automake libtool ninja-build \ flex bison \ texinfo git git-svn curl tar patchutils \ protobuf-compiler protobuf-c-compiler \ diff --git a/packaging/docker/Dockerfile.ubuntu b/packaging/docker/Dockerfile.ubuntu index b53631b31..633b98273 100644 --- a/packaging/docker/Dockerfile.ubuntu +++ b/packaging/docker/Dockerfile.ubuntu @@ -19,13 +19,13 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && \ apt-get install -y \ gcc g++ \ - pkg-config cmake make \ - autoconf automake autogen libtool \ + pkg-config cmake make meson \ + autoconf automake autogen libtool ninja-build \ texinfo git git-svn curl tar wget diffutils \ flex bison \ protobuf-compiler protobuf-c-compiler \ clang-format clangd \ - python3-venv \ + python3-venv unzip \ ninja-build mercurial \ xmlto udev From 0faa94b872c4d0d57e4b7f461d2d86774a6e7069 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Wed, 3 Sep 2025 13:28:39 +0200 Subject: [PATCH 4/7] fix(ci): Disable VILLAS_COMPILE_WARNING_AS_ERROR for debian, ubuntu and rocky Signed-off-by: Philipp Jungkamp --- .gitlab-ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a02ed3517..16df083a1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,7 +11,7 @@ variables: DOCKER_IMAGE_DEV: ${DOCKER_IMAGE}/dev-${DISTRO} DOCKER_CLI_EXPERIMENTAL: enabled CMAKE_BUILD_OPTS: "--parallel 16" - CMAKE_EXTRA_OPTS: "-DCMAKE_BUILD_TYPE=Release -DVILLAS_COMPILE_WARNING_AS_ERROR=ON" + CMAKE_EXTRA_OPTS: "-DCMAKE_BUILD_TYPE=Release" CACHIX_CACHE_NAME: villas stages: @@ -101,8 +101,12 @@ build:source: parallel: matrix: - DISTRO: [fedora, fedora-minimal, debian, rocky, ubuntu] + - DISTRO: fedora + CMAKE_EXTRA_OPTS: > + -DVILLAS_COMPILE_WARNING_AS_ERROR=ON - DISTRO: fedora-minimal - CMAKE_EXTRA_OPTS: -DVILLAS_COMPILE_WARNING_AS_ERROR=ON + CMAKE_EXTRA_OPTS: > + -DVILLAS_COMPILE_WARNING_AS_ERROR=ON -DWITH_API=OFF -DWITH_CLIENTS=OFF -DWITH_CONFIG=OFF From de90c96abe0fc50d427ecf0cc6092ed851d1e88a Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 9 Sep 2025 15:55:45 +0200 Subject: [PATCH 5/7] fix(fpga): Replace type-punning pointer cast with std::bit_cast Signed-off-by: Philipp Jungkamp --- fpga/src/villas-fpga-ctrl.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/fpga/src/villas-fpga-ctrl.cpp b/fpga/src/villas-fpga-ctrl.cpp index 05317524b..836cfe017 100644 --- a/fpga/src/villas-fpga-ctrl.cpp +++ b/fpga/src/villas-fpga-ctrl.cpp @@ -7,7 +7,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include +#include #include #include #include @@ -108,11 +108,7 @@ void readFromDmaToStdOut( try { for (size_t i = 0; i * 4 < c.bytes; i++) { int32_t ival = mem[cur][i]; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" - float fval = - *((float *)(&ival)); // cppcheck-suppress invalidPointerCast -#pragma GCC diagnostic pop + float fval = std::bit_cast(ival); formatter->format(fval); printf("%d: %#x\n", cnt++, ival); } From 2f24971d2ed70c8c47f6638e720d64c0d76ec3a9 Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 9 Sep 2025 18:08:02 +0200 Subject: [PATCH 6/7] fix(cppcheck): Suppress dangerous type cast warning Signed-off-by: Philipp Jungkamp --- lib/nodes/infiniband.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/nodes/infiniband.cpp b/lib/nodes/infiniband.cpp index 46adcb483..24b501e6b 100644 --- a/lib/nodes/infiniband.cpp +++ b/lib/nodes/infiniband.cpp @@ -772,7 +772,8 @@ int villas::node::ib_read(NodeCompat *n, struct Sample *const smps[], } // Get Memory Region - mr = memory::ib_get_mr(pool_buffer(sample_pool(smps[0]))); + mr = memory::ib_get_mr(pool_buffer( // cppcheck-suppress dangerousTypeCast + sample_pool(smps[0]))); for (int i = 0; i < max_wr_post; i++) { int j = 0; @@ -884,7 +885,8 @@ int villas::node::ib_write(NodeCompat *n, struct Sample *const smps[], // First, write // Get Memory Region - mr = memory::ib_get_mr(pool_buffer(sample_pool(smps[0]))); + mr = memory::ib_get_mr(pool_buffer( // cppcheck-suppress dangerousTypeCast + sample_pool(smps[0]))); for (sent = 0; sent < cnt; sent++) { int j = 0; From 67c3b5f0ac5a56cd68707f6bf4d626cdef0ce11c Mon Sep 17 00:00:00 2001 From: Philipp Jungkamp Date: Tue, 9 Sep 2025 20:33:34 +0200 Subject: [PATCH 7/7] fix(cppcheck): Replace string::find with string::starts_with Signed-off-by: Philipp Jungkamp --- lib/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config.cpp b/lib/config.cpp index dd149914e..97715d0a6 100644 --- a/lib/config.cpp +++ b/lib/config.cpp @@ -327,7 +327,7 @@ json_t *Config::expandIncludes(json_t *in) { std::string text = json_string_value(str); static const std::string kw = "@include "; - if (text.find(kw) != 0) + if (!text.starts_with(kw)) return json_incref(str); else { std::string pattern = text.substr(kw.size());