Defining variables within #if #else #endif in Arduino IDE

Chris picture Chris · Jan 27, 2015 · Viewed 16k times · Source

I was hoping that someone could shed light on why this code does not compile in Arduino IDE (using 1.0.5). The following code only compiles if DEBUG=1 but not if it is set to 0.

What I was hoping to achieve was just a simple way to use the same code when i swap LED drivers and just flip the DEBUG bit prior to recompiling and uploading.

Note: this sample is the whole code to be compiled in the IDE (no other code is required).

problem code:

#define DEBUG 0 //DEBUG=1 works, DEBUG=0 causes compiler error

#if DEBUG == 1
  int x = 123;
  //Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
#else
  int x = 567;
  //Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();
#endif

void setup() {  }

void loop() {  }

error:

core.a(main.cpp.o): In function `main':
C:\arduino\hardware\arduino\cores\arduino/main.cpp:11: undefined reference to `setup'
C:\arduino\hardware\arduino\cores\arduino/main.cpp:14: undefined reference to `loop'

Answer

Udo Klein picture Udo Klein · Jan 27, 2015

The reason is that the Arduino IDE sucks. Under the hood it generates c code like so

#define DEBUG 0 //DEBUG=1 works, DEBUG=0 causes compiler error

#if DEBUG == 1
  int x = 123;
  //Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
#else
  int x = 567;
  //Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();
#endif

void setup() {  }

void loop() {  }

Thus the compiler will not see the generated function prototypes if debug==0. Just set the compiler output to verbose and have a look yourself at the generated code in the build directory.

The solution to all this pain is to find some means to stop the IDE to mess with you stuff. I had some similar issue with function prototypes in the past that I solved with the TRICK17 macro (see here for the details). I will not go into the messy implementation of this macro as by now I found a significantly superior solution.

  • The IDE does not know about namespaces
  • As a consequence it does not touch anything inside namespaces
  • An empty namespace name is admissible this will establish an anonymous namespace. Entities in this namespace require no prefixes to address them.

Thus the new solution is

namespace {
// name of namespace left empty --> this is the anonymous namespace
// now the IDE will not mess with our stuff

#define DEBUG 0 //DEBUG=1 works, DEBUG=0 causes compiler error

#if DEBUG == 1
  int x = 123;
  //Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
#else
  int x = 567;
  //Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();
#endif
}

void setup() {  }

void loop() {  }