I have come across a side affect of the way arduino builds up a source file from multiple tabs that is unexpected and I wonder if its documented.
If two or more cpp files in the same sketch include the same header, it is not clear how the headers will be ordered in the amalgamated source file.
This becomes a problem when a header contains a conditional compile construct. For example if the header MyFile.h is something like:
int Foo = 1
#endif // MyFile_h
There is no obvious way to ensure that a specific source file can define ONLY_DECLARE_ONCE before some other file that includes MyFile.h blocks the check, which it will do when it includes Myfile.h and defines MyFile_h
I can work around this easily by moving the code within the ONLY_DECLARE_ONCE block to another file that is only included once, but this behavior seems unexpected.
Is this intended and is this documented?
I'm a bit confused.
If you have two files with a .cpp extension in your sketch, and each includes MyFile.h, then the contents of the file will be processed twice, once for each .cpp file (the MyFile_h definition only applies to any code below it, i.e. the individual .cpp file). If you #define ONLY_DECLARE_ONCE above the #include "MyFile.h" in a .cpp file, the foo variable will be defined for that .cpp file. If you have #define's in two .cpp files, the foo variable will be defined for both .cpp files, giving you an error that it was declared twice.
If you don't give your files a .cpp extension, they are all concatenated together with the main sketch file, in a random order. Is this the thing you're looking to control?
If you're trying to define a variable that's shared between multiple .cpp files, you want to define it as an extern in the header file, and only declare the variable normally in one .cpp file.
If that doesn't answer your question, please let me know.
The functionality I expected was to be able to define some things in the primary source file only (the .pde file) , but not in any other sketch source file (other cpp files in the sketch directory).
The reason for having the defines in an include file is that they need to be known to some non-arduino programs that are compiled adn run in a different environment.
I can create a separate file to solve this but having a single .h file that can be included by the PC program as well is a little more convenient. But the main reason for posting is that this behavour was unexpected and I wonder if it is documented.
Perhaps an example will be clearer, here are three files that when placed in a sketch directory will exhibit the behavour :
The sketch pde file
#define ONLY_DECLARE_ONCE // defining this should declare a variable Foo in Myfile.h
int ledPin = 13; // LED connected to digital pin 13
void setup() // run once, when the sketch starts
pinMode(ledPin, OUTPUT); // sets the digital pin as output
void loop() // run over and over again
digitalWrite(ledPin, HIGH); // sets the LED on
delay(Foo); // Foo should be declared in the MyFile.h !!!!!!!!!!!!!!!!!!!!
digitalWrite(ledPin, LOW); // sets the LED off
A cpp file in the same directory
// a cpp source file
// source code for this file doesn't matter
And MyFile.h that is included by both of the above :
int Foo = 1; // declare Foo in a file that has ONLY_DECLARE_ONCE defined
#endif // MyFile_h
Compiling this sketch will generate the message: error: 'Foo' was not declared in this scope
Ah, okay. The example helped a lot. Right now, the code lifts all #includes in the main sketch file to the top. I think this may be so that we can handle #include in any of the sketch files without extension (that all get concatenated together). Still, I can definitely see why it can be a problem to rearrange code like that. I need to take a closer look at this behavior soon - also because it's related to some issues we've had about the automatic generation of function prototypes and where they get placed in the generated code.
One solution could be to have a pragma to indicate the insertion point for the includes and prototypes. It's not very elegant but does enable some control for those situations where the insertion point matters.
Documenting the pragma would raise awareness of the unexpected behaviour and of course the pragma is not required for the large majority of programs that don't care about this issue.