From 33dcc49eba96202f4400a756c911b3c8d8f49b4b Mon Sep 17 00:00:00 2001 From: guicybercode Date: Sun, 20 Sep 2026 13:22:02 -0300 Subject: [PATCH] Fix build where major() and minor() are macros FreeBSD's and glibc's define major() and minor() as function-like macros and, unlike Apple's headers, keep them as macros in C++. nam::Version's member-initializer list read `major(major)`, which expanded, so NAM/get_dsp.h failed to compile for any consumer that included one of those headers first: NAM/get_dsp.h:30:5: error: expected class member or base class name Brace-init the members instead. A function-like macro only expands when the identifier is followed by `(`, so `major{major}` is left alone; `int major;`, `parsed.major` and `std::to_string(major)` never expanded to begin with, which makes lines 30-31 the only two expansion sites in the tree. The public members keep their names, so this is not an API break. The regression test defines the two macros itself rather than including , so it reproduces the FreeBSD/glibc preprocessor state on every platform, and is included first in run_tests.cpp so that NAM/get_dsp.h has not already been parsed by an earlier test. Validated on macOS/AppleClang: the new test fails to compile against the unmodified header with the error above, and the full run_tests suite, both benchmodel models and render all pass with the fix. Fixes #304 --- NAM/get_dsp.h | 10 ++++-- tools/run_tests.cpp | 4 +++ tools/test/test_get_dsp_sys_types.cpp | 45 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 tools/test/test_get_dsp_sys_types.cpp diff --git a/NAM/get_dsp.h b/NAM/get_dsp.h index 4783d71e..a49da706 100644 --- a/NAM/get_dsp.h +++ b/NAM/get_dsp.h @@ -26,10 +26,14 @@ class IVersionSupportChecker class Version { public: + // Brace-init the members rather than `major(major)`: (FreeBSD) + // and (glibc) define major() and minor() as function-like + // macros that stay macros in C++, and they expand on `major(`, breaking this + // header for any consumer that includes them first. `major{` does not expand. Version(int major, int minor, int patch) - : major(major) - , minor(minor) - , patch(patch) + : major{major} + , minor{minor} + , patch{patch} { } diff --git a/tools/run_tests.cpp b/tools/run_tests.cpp index ee827818..2895107d 100644 --- a/tools/run_tests.cpp +++ b/tools/run_tests.cpp @@ -2,6 +2,9 @@ // See the GitHub Action for a demo of how to build and run tests. #include +// Must come first: it checks that NAM/get_dsp.h parses while major()/minor() are +// macros, which only means anything if no earlier test has already included it. +#include "test/test_get_dsp_sys_types.cpp" #include "test/test_activations.cpp" #include "test/test_activations_realtime_safe.cpp" #include "test/test_conv1d.cpp" @@ -44,6 +47,7 @@ int main() { std::cout << "Running tests..." << std::endl; + test_get_dsp_sys_types::test_version_builds_with_major_minor_macros_defined(); test_get_dsp_wav::test_formats_and_configuration(); test_get_dsp_wav::test_invalid_files(); // TODO Automatically loop, catch exceptions, log results diff --git a/tools/test/test_get_dsp_sys_types.cpp b/tools/test/test_get_dsp_sys_types.cpp new file mode 100644 index 00000000..2ac7a6a0 --- /dev/null +++ b/tools/test/test_get_dsp_sys_types.cpp @@ -0,0 +1,45 @@ +// Regression test for issue #304. +// +// FreeBSD's and glibc's define major() and +// minor() as function-like macros, and unlike Apple's headers they keep them as +// macros in C++. Any consumer that includes one of those before NAM/get_dsp.h +// used to fail to compile, because nam::Version's member-initializer list read +// `major(major)` and the macro expanded. +// +// The macros are defined here rather than by including so the +// test reproduces the FreeBSD/glibc preprocessor state on every platform. They +// must go after get_dsp.h's dependency closure -- expanding them inside libc++'s +// own headers is a different, unrelated failure -- and are undefined at the end +// so they do not leak into the other tests included by run_tests.cpp. + +#include +#include +#include +#include +#include + +#include "NAM/dsp.h" +#include "NAM/nam_file.h" + +#define major(x) ((int)(((unsigned)(x) >> 24) & 0xff)) +#define minor(x) ((int)((x) & 0xffffff)) + +#include "NAM/get_dsp.h" + +#undef major +#undef minor + +namespace test_get_dsp_sys_types +{ +// Compiling this translation unit at all is the test; the assertions just keep +// the constructor from being optimized away and confirm the fields still land +// in the right order. +void test_version_builds_with_major_minor_macros_defined() +{ + const nam::Version version(1, 2, 3); + assert(version.major == 1); + assert(version.minor == 2); + assert(version.patch == 3); + assert(version.toString() == "1.2.3"); +} +} // namespace test_get_dsp_sys_types