AlexaLog: compile in projects that define DEBUG, ERROR or INFO as macros

8ea7778 introduced AlexaLogLevel::NONE, ERROR, INFO and DEBUG. A sketch that starts with "#define DEBUG 1", or a project built with -DDEBUG, did not compile any more: "expected identifier before numeric constant" at the enumerator, and with the build flag also in the library's own files, because ALEX2ESP_LOGD spelled AlexaLogLevel::DEBUG wherever it expanded. The same sketch builds against 1.1.0.

AlexaLog.h declares the enumerators between #pragma push_macro / #undef and #pragma pop_macro of the four names: a macro of the sketch is set aside for the declaration and is back after it. ALEX2ESP_LOG takes the level as its number and casts it, so no call site names an enumerator. AlexaLog.cpp, the one file that names the levels, undefines the four names after its includes.

For a sketch: nothing changes unless it defines such a macro. One that does cannot write AlexaLogLevel::DEBUG, because the preprocessor replaces the name; setLogLevel(static_cast<AlexaLogLevel>(3)) selects the same level. NONE is set aside in AlexaLog.h as well, but a project that defines NONE fails for another reason: AsyncMqttClient has an enumerator NONE (ParsingInformation.hpp).

Built for d1_mini with empty credentials (PlatformIO 6.2.0, espressif8266 4.2.1), examples/basicLight.cpp, static RAM / flash in bytes, 8ea7778 -> this commit, no warnings:
  as committed                                    34,116 / 336,757 -> 34,116 / 336,757
  "#define DEBUG 1" as the first line             does not compile -> 34,116 / 336,757
  DEBUG, ERROR and INFO defined in front          34,116 / 336,757
  build_flags = -DDEBUG                           does not compile (28 errors) -> 34,116 / 336,757
  build_flags = -DDEBUG -DERROR -DINFO            34,116 / 336,757
The other four examples are unchanged as well (34,232 / 340,517, 34,380 / 341,177, 34,024 / 335,457, 34,256 / 338,925).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 15:30:46 +00:00
parent 8ea777806a
commit 46a27c26e9
3 changed files with 41 additions and 12 deletions

View file

@ -1,6 +1,12 @@
#include "AlexaLog.h"
#include <stdarg.h>
// This file names the levels. A build flag such as -DDEBUG defines its macro here as well (see AlexaLog.h).
#undef NONE
#undef ERROR
#undef INFO
#undef DEBUG
AlexaLogLevel AlexaLog::level = AlexaLogLevel::INFO;
Print *AlexaLog::output = &Serial;

View file

@ -7,6 +7,20 @@
#include <Arduino.h>
// DEBUG, ERROR and INFO are names that sketches, build flags and other libraries define as macros ("#define DEBUG 1"
// in front of the includes is a common way to switch a sketch's own prints on). The enumerators are declared with
// those macros set aside, and the macros are put back after them. Code that has such a macro defined cannot spell
// the enumerator of that name; static_cast<AlexaLogLevel>(3) is the same level. NONE is set aside as well, but a
// project that defines it fails earlier: AsyncMqttClient has an enumerator of that name.
#pragma push_macro("NONE")
#pragma push_macro("ERROR")
#pragma push_macro("INFO")
#pragma push_macro("DEBUG")
#undef NONE
#undef ERROR
#undef INFO
#undef DEBUG
enum class AlexaLogLevel : uint8_t
{
NONE = 0, // nothing
@ -15,6 +29,11 @@ enum class AlexaLogLevel : uint8_t
DEBUG = 3 // sizes and free heap per message; needs ALEX2ESP_LOG_MAX=3
};
#pragma pop_macro("DEBUG")
#pragma pop_macro("INFO")
#pragma pop_macro("ERROR")
#pragma pop_macro("NONE")
// Highest level that is compiled in: 0 none, 1 ERROR, 2 INFO, 3 DEBUG. Override with -DALEX2ESP_LOG_MAX=<n> in
// build_flags. The Arduino IDE has no per-sketch flags and builds with this default.
#ifndef ALEX2ESP_LOG_MAX
@ -40,17 +59,21 @@ private:
static Print *output;
};
#define ALEX2ESP_LOG(levelNumber, levelName, format, ...) \
do \
{ \
if (ALEX2ESP_LOG_MAX >= (levelNumber) && AlexaLog::enabled(levelName)) \
{ \
AlexaLog::write(levelName, PSTR(format), ##__VA_ARGS__); \
} \
// The level is given as its number: these macros expand in every file that logs, also in one that is compiled
// with a DEBUG or ERROR macro of its own, so they must not spell an enumerator.
#define ALEX2ESP_LOG(levelNumber, format, ...) \
do \
{ \
if (ALEX2ESP_LOG_MAX >= (levelNumber) && \
AlexaLog::enabled(static_cast<AlexaLogLevel>(levelNumber))) \
{ \
AlexaLog::write(static_cast<AlexaLogLevel>(levelNumber), \
PSTR(format), ##__VA_ARGS__); \
} \
} while (0)
#define ALEX2ESP_LOGE(format, ...) ALEX2ESP_LOG(1, AlexaLogLevel::ERROR, format, ##__VA_ARGS__)
#define ALEX2ESP_LOGI(format, ...) ALEX2ESP_LOG(2, AlexaLogLevel::INFO, format, ##__VA_ARGS__)
#define ALEX2ESP_LOGD(format, ...) ALEX2ESP_LOG(3, AlexaLogLevel::DEBUG, format, ##__VA_ARGS__)
#define ALEX2ESP_LOGE(format, ...) ALEX2ESP_LOG(1, format, ##__VA_ARGS__)
#define ALEX2ESP_LOGI(format, ...) ALEX2ESP_LOG(2, format, ##__VA_ARGS__)
#define ALEX2ESP_LOGD(format, ...) ALEX2ESP_LOG(3, format, ##__VA_ARGS__)
#endif // ALEXA_LOG_H