Suppose I pick the UNO R3 board from Boards Manager. I would expect this to select the header included in the first condition but ignore the one in the second condition. Instead, it would appear that both are being compiled, which results in errors relating to resources that are only available for the board type relating to the file being included for the second condition (e.g. DDRE register).
Why is the compiler trying to compile both sets of .h/.cpp files?
I can probably prevent that by adding further defines and guards in both .h and .cpp files but I would have thought the conditional #ifdef as per the above would have been sufficient to include and compile ONLY the files selected by the conditional statement?
Just to add, that even if I comment out the two #include statements, the compiler is still trying to compile the files. It doesn't matter where the files are located within the sketch directory either. The only solution I have found so far to avoid a clash, is to comment out the includes and remove the files completely from the Sketch directory - or else use additional #define ... #ifdef ... guards.
That's a good observation and makes things look more consistent so I have added the keyword defined and put the term in brackets as shown but that has not changed the behavior of the compiler unfortunately.
Aside from the #elif issue that has already been clarified, if a *.h still compiles even if you remove your #include statements, clearly some other module does just that.
Since I don't have your entire sketch I can't say which one, anyway you just need to examine all the *.h files you include and see who is the "culprit" and try to correct it from there (if it's possible).
This example illustrates the problem. It has no directory structure, just one flat project directory. Doesn't matter if you comment out one or the other or both of the defines, you still get the same errors due to the clash of function names, showing that both are being compiled regardless. If I comment out both, then you do get the expected 'func was not declared in this scope' errors:
INO:
#define INCLUDE1
//#define INCLUDE2
#ifdef INCLUDE1
#include "include1.h"
#elif defined(INCLUDE2)
#include "include2.h"
#endif
// The setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
delay(500);
func1();
func2();
#ifdef INCLUDE2
funcX();
#endif
Serial.flush();
}
// The loop function runs continuously
void loop() {
}
#include "include1.h"
void func1(){
Serial.println(F("This is include 1 function 1"));
}
void func2(){
Serial.println(F("This is include 1 function 2"));
}
#include "include2.h"
void func1(){
Serial.println(F("This is include 2 function 1"));
}
void func2(){
Serial.println(F("This is include 2 function 2"));
}
void funcX(){
Serial.println(F("This is include 2 function X"));
}
I tried putting the files in separate directories as suggested, but that did not resolve the problem.`
I just tried the same example in OnlineGDB.com, but replacing occurrences of Serial.println() with std::cout and got the same result, which rules out the IDE. It seems you are correct. Its just the way that the compiler deals with project files. It processes all files present regardless of whether they are #include(ed) or not, so I guess additional guards will be necessary after all.
Your problem is not the compiler but the linker. Your ino file compiles ok, and so do both .cpp files. But if the linker wants to put it all together, it complains about the different functions with the same name in the two .cpp files. It has nothing to do with the #ifdef in the .ino file. Its simply the two .cpp files having different functions with the same name.
I get that and yes its the linker not the compiler complaining. I stand corrected. However, I was expecting to take one file or the other out of the picture by commenting out or conditionally excluding it (by not including it), but that is evidently not how it works. It seems whether included or not, all files get processed by compiler - and linker - if they are in the project directory, regardless of whether they are #included or not, which is useful to be aware of.
I guess that does answer my question, even if the answer is not quite what I had expected, so thank you for the comments.
But that happens ONLY in the .ino file. When the compiler compiles your .cpp files it knows nothing about that, nor does the linker when it links everything together.
You need to check the board defines also in your .cpp files to compile only the board relevant functions.
Yes, that is the only other options and I have done that but the linker now complains about undefined references to functions inside the conditional statements which is where this all started.
Having spent all day on this I am back to square one....
The easiest thing is to just leave things as they were. I had hoped to make this a little more structured and easier to work with. Didn't think it would end up being quite this complicated.
Well, obviously you can't attempt to call a function which does not exist due to conditional compilation. The call itself must be conditionally compiled.
Yes, agreed, but the functions do exist and should be visible to the linker. They are selected depending on the board platform being used, and there will always be a board platform selected so at least one group of functions will always exist. The calls always match the entry functions regardless of which platform is used.
The problem I currently have is that although the pin definitions in the .h file are being read (there were no errors relating to them), the linker complains about the functions in the corresponding .cpp file not existing, but how can that be, since the contents of the header file matches the condition and have been read? How can it work fine for one instance of a conditional compilation but fail for another instance of the same condition? The condition is identical in both files.
#define INCLUDE1
//#define INCLUDE2
#ifdef INCLUDE1
#include "src/include1/include1.h"
#elif defined(INCLUDE2)
#include "src/include2/include2.h"
#endif
// The setup function runs once when you press reset or power the board
void setup() {
Serial.begin(115200);
delay(500);
func1();
func2();
#ifdef INCLUDE2
funcX();
#endif
Serial.flush();
}
// The loop function runs continuously
void loop() {
}
#include "include1.h"
#ifdef INCLUDE1
void func1(){
Serial.println(F("This is include 1 function 1"));
}
void func2(){
Serial.println(F("This is include 1 function 2"));
}
#endif
#include "include2.h"
#ifdef INCLUDE2
void func1(){
Serial.println(F("This is include 2 function 1"));
}
void func2(){
Serial.println(F("This is include 2 function 2"));
}
void funcX(){
Serial.println(F("This is include 2 function X"));
}
#endif // INCLUDE2
BTW, I have tried placing all files into the root sketch directory and obviously changing the #inlcude path,, but same result, so the problem does not appear to be being caused by the directory structure.