I'm looking at a project which has two ino files in the project directory.
I see the build files in the temporary location for the main sketch but not for the other ino file. However, it is clear that content of the second file is magically included.
There does not seem to be an #include to pull it in, so it seems the IDE does this by hidden magic.
How is this done and in what order?
I'm trying to combine them into one ino file but can't work out which code gets compiled first to get things in the right place.
The IDE combines all ino files into one big file with the original file name (sketch.ino) followed by the extension.cpp. As you have found that big file, you can have a look with a text editor what is in there; you can see the sequence in there as well. If I recall correctly the sequence is main sketch followed by alphabetically ordered other ino files.
This only applies to ino files, not to .c/.cpp/.h files.
Note:
Multiple inos can result in unexpected compile errors. E.g. if you create an original sketch and later split it over multiple ino files you might get errors.
You should not need to "get things in the right place" in your combined sketch file beyond declaring global variables and #defining values before they are used, as normal
The IDE adds function definitions to the sketch if they are not already present. I have only ever encountered problems when using functions with default values for parameters and I believe that this may have been fixed too
Nah, it's more complicated than that. That was my initial assumption but that produced a ton of compiler errors.
you can have a look with a text editor what is in there
Excellent tip. I found that there is some heavy code snipping where each mod is prefixed with a "#line xxx" marker. They seem to include forward declarations for all fns in both ino files.
My recommendation it to not use multiple .ino files. Set up proper .cpp and .h files and use the header file includes in the .ino file. Then you don't have to worry about IDE weirdness and it is easier to reuse the code in other projects.
The purpose of the added #line directives is to cause the line numbers specified in messages from the compiler to match the user's sketch code, rather than the line numbers of the C++ file generated by the sketch preprocessor that is actually being compiled.
Thanks for that link. Nicely and clearly documented.
I used the headers created in the .ino.cpp and pasted them to my .ino which saved me quite a lot of typing ( mostly unnecessary for the base ino functions, but what the hell ).
Now the .ino.cpp does not add anything else. That allowed me to just concatenate the two files in one .ino . All much cleaner and less mumbo jumbo during compilation.
Yes, that makes a lot more sense. This is the first time I'd come across a double ino and I could not work out how it was handled by behind the scenes mojo. Already the does not help in following the code.
I see no reason not to explicitly write the fn prototypes and use #include in the standard way. This kind of "make it easy by hiding what is really happening" is rarely helpful or educational IMHO.
That is not part of the sketch build system, so it is out of scope for that document.
The main function is implemented in the platform's core. The main function calls the setup and loop functions, which should be implemented in the sketch.
For example, you can see the main function in the core of the "Arduino AVR Boards" platform here:
Unfortunately we don't currently have any formal documentation of the internal interfaces like this that should be implemented in Arduino cores, so the best we have right now is the official cores serving as a reference for core developers. We are tracking the need to create such documentation here:
Not sure if I understand the question. main.c (or main.cpp) is part of the core; the relevant content for the AVR core is shown below, other cores will be similar.
#include <Arduino.h>
// Declared weak in Arduino.h to allow user redefinitions.
int atexit(void (* /*func*/ )()) { return 0; }
// Weak empty variant initialization function.
// May be redefined by variant files.
void initVariant() __attribute__((weak));
void initVariant() { }
void setupUSB() __attribute__((weak));
void setupUSB() { }
int main(void)
{
init();
initVariant();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
You might know the below.
.c/.cpp files are compiled as compilation units. setup() and loop() are declared in Arduino.h so the above file can be compiled.
At the end the linker will combine all compiled compilation units (so that includes the compiled *yourSketch.ino.cpp).
Look in the core files. I only use AVR based boards but have some stuff installed. Below a list of files that contain the word setup1; this is for a portable installation of IDE 1.8.19 on my Windows system so your path will more than likely differ.