Skip to content

Commit a3e29f0

Browse files
replaced {fmt} by <format> and <print>
* requires Clang >=18 (libc++) and GCC >=14 (stdlibc++) * bumped boost/ut to v2.3.1 (latest as of 2023-04-02) * bumped vir-simd to v0.4.4 (latest as of 2025-05-10, thanks to @mattkretz) * fixed stricter formatting and consteval-related rule issues * updated docker image to Ubuntu 25.04 (valid for 9 month) * added gcc-15 and clang-20 dependencies * disabled/removed `-lto` flags due to LLVM/mold bug (not yet deployed: https://github.com/rui314/mold/releases/tag/v2.39.1) Signed-off-by: Ralph J. Steinhagen <[email protected]> Signed-off-by: rstein <[email protected]> Signed-off-by: Ralph J. Steinhagen <[email protected]>
1 parent 9ff047e commit a3e29f0

File tree

142 files changed

+1823
-1623
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+1823
-1623
lines changed

.github/workflows/ci.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,15 @@ jobs:
7676
- cc: gcc-14
7777
cxx: g++-14
7878
cmake_flags: "-DADDRESS_SANITIZER=ON"
79-
- cc: gcc-13
80-
cxx: g++-13
81-
cmake_flags: "-DADDRESS_SANITIZER=OFF"
79+
- cc: gcc-15
80+
cxx: g++-15
81+
cmake_flags: "-DADDRESS_SANITIZER=ON"
8282
- cc: clang-18
8383
cxx: clang++-18
8484
cmake_flags: "-DADDRESS_SANITIZER=ON -DCMAKE_LINKER=/usr/bin/clang-18"
85+
- cc: clang-20
86+
cxx: clang++-20
87+
cmake_flags: "-DADDRESS_SANITIZER=ON -DCMAKE_LINKER=/usr/bin/clang-20"
8588
- cmake_wrapper: emcmake
8689
cc: emcc
8790
cmake_flags: "-DENABLE_COVERAGE=OFF -DCMAKE_CROSSCOMPILING_EMULATOR=${SYSTEM_NODE} -DGNURADIO_PARSE_REGISTRATIONS_TOOL_CXX_COMPLILER=g++-14"
@@ -164,7 +167,7 @@ jobs:
164167
if: matrix.compiler.cmake_wrapper != null
165168
working-directory: ${{runner.workspace}}/build
166169
shell: bash
167-
run: node --experimental-wasm-threads ./core/src/main.js
170+
run: node ./core/src/main.js
168171

169172
- name: Show final ccache stats
170173
run: ccache --show-stats

CMakeLists.txt

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,6 @@ if(NOT MSVC)
3131

3232
set(_LD_GC_SECTIONS "-Wl,--gc-sections -ffunction-sections -fdata-sections")
3333

34-
if(NOT EMSCRIPTEN)
35-
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
36-
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13
37-
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15)
38-
message(STATUS "GCC <15 detected – disabling LTO due to known IPA/modref crash issues.")
39-
else()
40-
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -flto=auto -fno-fat-lto-objects")
41-
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -flto=auto -fno-fat-lto-objects")
42-
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -flto=auto -fno-fat-lto-objects")
43-
set(_LD_GC_SECTIONS "${_LD_GC_SECTIONS} -flto=auto -fno-fat-lto-objects")
44-
endif()
45-
endif()
46-
4734
find_program(MOLD_BIN ld.mold)
4835
if(MOLD_BIN)
4936
set(_LD_GC_SECTIONS "${_LD_GC_SECTIONS} -fuse-ld=mold")
@@ -305,54 +292,39 @@ target_include_directories(exprtk PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/third_part
305292
"${CMAKE_CURRENT_SOURCE_DIR}/third_party/exprtk")
306293
if(EMSCRIPTEN)
307294
target_compile_options(exprtk PRIVATE -O1 -g0)
308-
elseif(
309-
CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
310-
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13
311-
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS_EQUAL 14)
312-
message(STATUS "GCC <15 detected – disabling LTO for exprtk due to known IPA/modref crash issues.")
295+
elseif()
313296
target_compile_options(exprtk PRIVATE -O1 -g0 -fvisibility=hidden)
314-
else()
315-
target_compile_options(
316-
exprtk
317-
PRIVATE -O1
318-
-g0
319-
-flto=auto
320-
-ffat-lto-objects
321-
-fvisibility=hidden)
322297
endif()
323298
set_source_files_properties(third_party/exprtk.cpp PROPERTIES COMPILE_OPTIONS "-fvisibility=hidden")
324299
# include exprtk header-only - END
325300

326301
include(FetchContent)
327-
FetchContent_Declare(
328-
fmt
329-
GIT_REPOSITORY https://github.com/fmtlib/fmt.git
330-
GIT_TAG 10.2.1)
331-
332302
FetchContent_Declare(
333303
pmt
334304
GIT_REPOSITORY https://github.com/gnuradio/pmt.git
335305
GIT_TAG e1a46cb61decb044f6ab0a58a77211beb3630340 # latest as of 2023-12-06
336306
)
337307

308+
set(BOOST_UT_DISABLE_MODULE
309+
ON
310+
CACHE BOOL "Disable UT Module Support" FORCE)
338311
FetchContent_Declare(
339312
ut
340313
GIT_REPOSITORY https://github.com/boost-ext/ut.git
341-
GIT_TAG v2.0.1 # latest tag as of 2023-12-18
314+
GIT_TAG 53e17f25119598c6458d30351b260193096ba67e # latest tag as of 2023-04-02
342315
)
343316

344317
FetchContent_Declare(
345318
vir-simd
346319
GIT_REPOSITORY https://github.com/mattkretz/vir-simd.git
347-
GIT_TAG v0.4.0)
320+
GIT_TAG v0.4.4)
348321

349322
FetchContent_Declare(
350323
cpp-httplib
351324
GIT_REPOSITORY https://github.com/yhirose/cpp-httplib.git
352325
GIT_TAG v0.18.1)
353326

354327
FetchContent_MakeAvailable(
355-
fmt
356328
pmt
357329
ut
358330
vir-simd

algorithm/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ target_link_libraries(
77
gnuradio-meta
88
vir
99
fftw
10-
fmt
1110
magic_enum)
1211

1312
if(ENABLE_EXAMPLES)

algorithm/include/gnuradio-4.0/algorithm/ImChart.hpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
#include <sys/ioctl.h>
1212
#include <vector>
1313

14-
#include <fmt/format.h> // TODO: remove for fmt::print until std::format and std::print is available in gcc & emscripten
14+
#include <format>
1515
#ifdef __GNUC__
1616
#pragma GCC diagnostic push // ignore warning of external libraries that from this lib-context we do not have any control over
1717
#ifndef __clang__
@@ -76,7 +76,7 @@ struct LogAxisTransform {
7676
template<typename T>
7777
[[nodiscard]] static constexpr std::size_t toScreen(T value, T axisMin, T axisMax, std::size_t screenOffset, std::size_t screenSize) {
7878
if (value <= 0 || axisMin <= 0 || axisMax <= axisMin) {
79-
throw std::invalid_argument(fmt::format("{} not defined for non-positive value {} in [{}, {}].", gr::meta::type_name<LogAxisTransform>(), value, axisMin, axisMax));
79+
throw std::invalid_argument(std::format("{} not defined for non-positive value {} in [{}, {}].", gr::meta::type_name<LogAxisTransform>(), value, axisMin, axisMax));
8080
}
8181

8282
const T log_min = std::log10(axisMin);
@@ -87,7 +87,7 @@ struct LogAxisTransform {
8787
template<std::floating_point T>
8888
[[nodiscard]] static constexpr T fromScreen(std::size_t screenCoordinate, T axisMin, T axisMax, std::size_t screenOffset, std::size_t screenSize) {
8989
if (axisMin <= 0UZ || axisMax <= axisMin) {
90-
throw std::invalid_argument(fmt::format("{} not defined for non-positive ranges [{}, {}].", gr::meta::type_name<LogAxisTransform>(), axisMin, axisMax));
90+
throw std::invalid_argument(std::format("{} not defined for non-positive ranges [{}, {}].", gr::meta::type_name<LogAxisTransform>(), axisMin, axisMax));
9191
}
9292

9393
const T proportion = static_cast<T>(screenCoordinate - screenOffset) / (static_cast<T>(screenSize - screenOffset - 1UZ)); // convert screen coordinates back to a proportion of the axis
@@ -117,7 +117,7 @@ inline std::vector<std::size_t> optimalTickScreenPositions(std::size_t axisWidth
117117

118118
} // namespace detail
119119

120-
inline void resetView() { fmt::println("\033[2J\033[H"); }
120+
inline void resetView() { std::puts("\033[2J\033[H"); }
121121

122122
/**
123123
* @brief compact class for ASCII charting in terminal environments, supporting custom dimensions and styles.
@@ -337,15 +337,18 @@ struct ImChart {
337337
if (!datasetInvolved) {
338338
continue;
339339
}
340-
const auto colourStr = Color::get(_lastColor);
341-
constexpr auto defaultColour = Color::get(Color::Type::Default);
342-
auto& screen = _screen[bRowIdx / kCellHeight][bColIdx / kCellWidth];
340+
const auto colourStr = Color::get(_lastColor);
341+
auto& screen = _screen[bRowIdx / kCellHeight][bColIdx / kCellWidth];
342+
screen.clear();
343+
screen += colourStr;
344+
343345
switch (style) {
344-
case Style::Bars: screen.assign(fmt::format("{}{}{}", colourStr, kBars[dot], defaultColour)); break;
345-
case Style::Marker: screen.assign(fmt::format("{}{}{}", colourStr, kMarker[_n_datasets - 1], Color::get(Color::Type::Default))); break;
346+
case Style::Bars: screen += kBars[dot]; break;
347+
case Style::Marker: screen += kMarker[_n_datasets - 1]; break;
346348
case Style::Braille:
347-
default: screen.assign(fmt::format("{}{}{}", colourStr, kBrailleCharacter[dot], Color::get(Color::Type::Default))); break;
349+
default: screen += kBrailleCharacter[dot]; break;
348350
}
351+
screen += Color::get(Color::Type::Default);
349352
}
350353
}
351354
_lastColor = Color::next(_lastColor);
@@ -368,17 +371,17 @@ struct ImChart {
368371
_n_datasets = 0UZ;
369372
}
370373

371-
void reset() const noexcept { fmt::print("\033[0;0H"); }
374+
void reset() const noexcept { std::puts("\033[0;0H"); }
372375

373376
void printScreen() const noexcept {
374377
for (const auto& row : _screen) {
375378
for (const auto& cell : row) {
376-
fmt::print("{}", cell);
379+
std::fwrite(cell.data(), 1, cell.size(), stdout);
377380
}
378-
fmt::print("\n");
381+
std::fputs("\n", stdout);
379382
}
380383
// Reset terminal colour after printing
381-
fmt::print("{}", Color::get(Color::Type::Default));
384+
std::fputs(Color::get(Color::Type::Default), stdout);
382385
}
383386

384387
void printSourceLocation() {
@@ -389,7 +392,7 @@ struct ImChart {
389392
std::size_t cutPosition = fullPath.find_last_of('/', fullPath.size() - maxLength);
390393
fullPath = (cutPosition != std::string::npos) ? "[..]" + fullPath.substr(cutPosition) : std::move(fullPath);
391394
}
392-
std::string srcLocation = fmt::format("{}:{}", fullPath, _location.line());
395+
std::string srcLocation = std::format("{}:{}", fullPath, _location.line());
393396

394397
// calculate starting position, clamping to screen width
395398
std::size_t startX = std::max(0LU, _screen_width - srcLocation.size() - 1UZ);
@@ -409,7 +412,7 @@ struct ImChart {
409412
[[nodiscard]] constexpr std::size_t getVerticalAxisPositionX() const noexcept {
410413
auto y_axis_x = std::is_same_v<horAxisTransform, LogAxisTransform> ? 0UZ : static_cast<std::size_t>((std::max(0. - axis_min_x, 0.) / (axis_max_x - axis_min_x)) * static_cast<double>(_screen_width - 1UZ));
411414
// adjust for axis labels
412-
std::size_t y_label_width = std::max(fmt::format("{:G}", axis_min_y).size(), fmt::format("{:G}", axis_max_y).size());
415+
std::size_t y_label_width = std::max(std::format("{:G}", axis_min_y).size(), std::format("{:G}", axis_max_y).size());
413416
return std::clamp(y_axis_x, y_label_width + 3, _screen_width); // Ensure axis positions are within screen bounds
414417
}
415418

@@ -428,7 +431,7 @@ struct ImChart {
428431
}
429432

430433
// x-axis labels and ticks
431-
const std::size_t maxHorLabelWidth = std::max(fmt::format("{:+G}", axis_min_x).size(), fmt::format("{:+G}", axis_max_x).size());
434+
const std::size_t maxHorLabelWidth = std::max(std::format("{:+G}", axis_min_x).size(), std::format("{:+G}", axis_max_x).size());
432435
for (const auto& relTickScreenPos : detail::optimalTickScreenPositions(_screen_width - horOffset, 1UZ)) {
433436
const std::size_t tickPos = horOffset + relTickScreenPos;
434437
const double tickValue = horAxisTransform::fromScreen(tickPos, axis_min_x, axis_max_x, horOffset, _screen_width);
@@ -437,8 +440,8 @@ struct ImChart {
437440
}
438441
_screen[horAxisPosY][tickPos] = relTickScreenPos == 0 ? "" : ((tickPos + 1) >= _screen_width) ? "" : ""; // NOSONAR
439442

440-
const std::string rawLabel = axis_min_x < 0 ? fmt::format("{:+G}", tickValue) : fmt::format("{:G}", tickValue);
441-
const std::string label = fmt::format("{:.{}}", rawLabel, maxHorLabelWidth);
443+
const std::string rawLabel = axis_min_x < 0 ? std::format("{:+G}", tickValue) : std::format("{:G}", tickValue);
444+
const std::string label = std::format("{:.{}}", rawLabel, maxHorLabelWidth);
442445

443446
// Calculate the start and end positions for the label to be centred around tickPos and clamp to ensure they're within screen bounds
444447
const std::size_t start_pos = std::clamp((tickPos >= label.size() / 2) ? tickPos - label.size() / 2 : 0, 0UZ, _screen_width - label.size());
@@ -458,8 +461,8 @@ struct ImChart {
458461
}
459462
_screen[tickPos][verAxisPosX] = relTickScreenPos == 0 ? "" : (tickPos < _screen_height) ? "" : (axis_max_y == 0) ? "" : ""; // NOSONAR
460463

461-
const std::string rawLabel = axis_min_y < 0 ? fmt::format("{:+G}", tickValue) : fmt::format("{:G}", tickValue);
462-
const std::string label = fmt::format("{:.{}}", rawLabel, verAxisPosX - 2UZ);
464+
const std::string rawLabel = axis_min_y < 0 ? std::format("{:+G}", tickValue) : std::format("{:G}", tickValue);
465+
const std::string label = std::format("{:.{}}", rawLabel, verAxisPosX - 2UZ);
463466

464467
// Calculate the starting position for the label ensuring it's within bounds.
465468
const std::size_t label_start_pos = (verAxisPosX > label.size() + 1UZ) ? verAxisPosX - label.size() - 1UZ : 0UZ;

algorithm/include/gnuradio-4.0/algorithm/dataset/DataSetEstimators.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
#include <string_view>
1616
#include <vector>
1717

18-
#include <fmt/format.h>
18+
#include <format>
1919

2020
#include <gnuradio-4.0/DataSet.hpp>
2121
#include <gnuradio-4.0/Message.hpp>
@@ -472,7 +472,7 @@ template<MetaInfo mode = MetaInfo::Apply, DataSetLike D, typename T = typename s
472472
const std::uint64_t period = 1'000'000'000;
473473
const std::uint64_t time = static_cast<std::uint64_t>(gr::value(value)) * period;
474474
const std::uint64_t timeUncertainty = static_cast<std::uint64_t>(gr::uncertainty(value)) * period;
475-
property_map data = property_map{{gr::tag::TRIGGER_NAME.shortKey(), fmt::format("{}_EDGE_LEVEL_{}", isRising ? "RISING" : "FALLING", threshold)}, //, //
475+
property_map data = property_map{{gr::tag::TRIGGER_NAME.shortKey(), std::format("{}_EDGE_LEVEL_{}", isRising ? "RISING" : "FALLING", threshold)}, //, //
476476
{gr::tag::TRIGGER_TIME.shortKey(), time}, {"trigger_time_error", timeUncertainty}, {gr::tag::TRIGGER_OFFSET.shortKey(), 0.f}, //
477477
{gr::tag::CONTEXT.shortKey(), context}};
478478
dataSet.timing_events[signalIndex].push_back({idx, std::move(data)});
@@ -495,7 +495,7 @@ std::optional<StepStartDetectionResult<T>> detectStepStart(D& ds, TValue thresho
495495

496496
std::expected<void, gr::Error> dsCheck = gr::dataset::checkConsistency(ds, "", location);
497497
if (!dsCheck.has_value()) {
498-
throw gr::exception(fmt::format("Invalid DataSet for step/pulse start detection: {}", dsCheck.error()), location);
498+
throw gr::exception(std::format("Invalid DataSet for step/pulse start detection: {}", dsCheck.error()), location);
499499
}
500500
indexMax = detail::checkIndexRange(ds, indexMin, indexMax, signalIndex, location);
501501

@@ -543,7 +543,7 @@ std::optional<StepStartDetectionResult<T>> detectStepStart(D& ds, TValue thresho
543543
const std::uint64_t period = 1'000'000'000;
544544
const std::uint64_t time = static_cast<std::uint64_t>(gr::value(xAxis[index])) * period;
545545
const std::uint64_t timeUncertainty = 0UZ;
546-
property_map data = property_map{{gr::tag::TRIGGER_NAME.shortKey(), fmt::format("{}_EDGE_LEVEL_{}", isRising ? "RISING" : "FALLING", threshold)}, //
546+
property_map data = property_map{{gr::tag::TRIGGER_NAME.shortKey(), std::format("{}_EDGE_LEVEL_{}", isRising ? "RISING" : "FALLING", threshold)}, //
547547
{gr::tag::TRIGGER_TIME.shortKey(), time}, {"trigger_time_error", timeUncertainty}, {gr::tag::TRIGGER_OFFSET.shortKey(), 0.f}, //
548548
{gr::tag::CONTEXT.shortKey(), context}};
549549
ds.timing_events[signalIndex].push_back({index, std::move(data)});

algorithm/include/gnuradio-4.0/algorithm/dataset/DataSetHelper.hpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ std::size_t checkIndexRange(const DataSet<T>& ds, std::size_t minIndex = 0UZ, st
3131
maxIndex = maxDataSetIndex;
3232
}
3333
if (minIndex > maxIndex || minIndex >= maxDataSetIndex || maxIndex > maxDataSetIndex || signalIndex >= ds.size()) {
34-
throw gr::exception(fmt::format("DataSet<{}> ({}/{}: \"{}\") indices [{}, {}] out of range [0, {}]", //
34+
throw gr::exception(std::format("DataSet<{}> ({}/{}: \"{}\") indices [{}, {}] out of range [0, {}]", //
3535
gr::meta::type_name<T>(), signalIndex, ds.size(), signalIndex < ds.size() ? ds.signalName(signalIndex) : "???", //
3636
minIndex, maxIndex, maxDataSetIndex),
3737
location);
@@ -74,7 +74,7 @@ template<typename T, typename TValue = gr::meta::fundamental_base_value_type_t<T
7474
return static_cast<T>(vals[sampleIndex]);
7575
}
7676

77-
throw gr::exception(fmt::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
77+
throw gr::exception(std::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
7878
}
7979

8080
template<typename T>
@@ -88,7 +88,7 @@ T getDistance(const DataSet<T>& dataSet, std::size_t dimIndex, std::size_t index
8888
return getIndexValue(dataSet, dimIndex, indexMax, signalIndex) - getIndexValue(dataSet, dimIndex, indexMin, signalIndex);
8989
}
9090

91-
throw gr::exception(fmt::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
91+
throw gr::exception(std::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
9292
}
9393

9494
/*!
@@ -145,7 +145,7 @@ template<typename T, typename TValue = gr::meta::fundamental_base_value_type_t<T
145145
return yLow + t * (yHigh - yLow);
146146
}
147147

148-
throw gr::exception(fmt::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
148+
throw gr::exception(std::format("axis dimIndex {} is out of range [0, {}] and", dimIndex, dataSet.axisCount()));
149149
}
150150

151151
template<typename T>
@@ -181,14 +181,16 @@ template<typename T>
181181

182182
template<typename T>
183183
[[nodiscard]] std::expected<void, gr::Error> checkConsistency(const DataSet<T>& ds, std::string_view dsName = "unnamed", std::source_location location = std::source_location::current()) {
184-
auto handleFailure = [&]<typename... Args>(std::string_view fmtStr, Args&&... args) -> std::expected<void, gr::Error> {
185-
std::string combinedFmt = "Mismatch in DataSet<{}>-\"{}\": " + std::string(fmtStr) + "\n";
186-
return std::unexpected(gr::Error(fmt::format(fmt::runtime_format_string<>(combinedFmt), gr::meta::type_name<T>(), dsName, std::forward<Args>(args)...), location));
184+
auto handleFailure = [&](std::string_view fmtStr, auto&&... args) -> std::expected<void, gr::Error> {
185+
auto formatted = std::vformat(fmtStr, std::make_format_args(args...));
186+
auto fullMsg = std::format("Mismatch in DataSet<{}>-\"{}\": {}\n", gr::meta::type_name<T>(), dsName, formatted);
187+
return std::unexpected(gr::Error(std::move(fullMsg), location));
187188
};
188189

189190
// check all extents are non-negative
190-
if (std::ranges::any_of(ds.extents, [](std::int32_t e) { return e <= 0; })) {
191-
return handleFailure("found 0 or negative extend values [{}]", fmt::join(ds.extents, ", "));
191+
if (std::ranges::any_of(ds.extents, [](std::int32_t e) { return e <= 0; })) { // clang-20 bug workaround "immediate function 'operator()<const std::string &>' used before it is defined"
192+
// return std::unexpected(gr::Error(std::format("Mismatch in DataSet<{}>-\"{}\": found bad extents [{}]\n", gr::meta::type_name<T>(), dsName, gr::join(ds.extents, ", ")), location));
193+
return handleFailure("found 0 or negative extent values [{}]", gr::join(ds.extents));
192194
}
193195

194196
// check axis-related sizes: axisCount() == extents.size() == axis_units.size() == axis_values.size()

0 commit comments

Comments
 (0)