Arduino tabs doing weird things.

Just started on my first large project, a RC Transmitter, and decided to try using tabs in the Arduino IDE to help me separate blocks of code up logically.

I have not given the tabs file extensions making them all .ino files meaning the IDE should compile them together starting with the project main file(the one with the same name as the folder) followed by the rest in alphabetical order.

So I have started writing up some code but have found a strange issue.

If i add the below function into the bottom of the first tab it compiles file. I don't know if it makes a difference but nothing in my program is currently calling this function.

void AnalogChannelRead(AnalogCHConfig &Test)
{
  Test.LowerCali = 100;
  Test.HighCali  = 500;
}

But if I put the same function in the top of the second tab instead it errors when trying to compile. According to the information I found above on how tabs without file extensions work it should make no difference as this function will be in the exact same place once the compiler combines all the .ino files together.

Can somebody please explain what is actually going on here as I am about to pull my hair out.

IDE error message

Arduino: 1.8.12 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"

b1_test:1:24: error: variable or field 'AnalogChannelRead' declared void

 void AnalogChannelRead(AnalogCHConfig &Test)

                        ^~~~~~~~~~~~~~

b1_test:1:24: error: 'AnalogCHConfig' was not declared in this scope

b1_test:1:40: error: 'Test' was not declared in this scope

 void AnalogChannelRead(AnalogCHConfig &Test)

                                        ^~~~

exit status 1
variable or field 'AnalogChannelRead' declared void

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

At the start of compilation, the Arduino IDE makes some small changes to your .ino files to ensure it's valid C++. It will add function prototypes for any function that doesn't already have one. This is intended to make it easier for beginners to write code in the Arduino IDE, and also automates a tedious task. After inserting the function prototypes, the IDE adds #line directives so that error/warning messages will still match your sketch. In some rare cases, the Arduino IDE does not take the correct action during function prototype generation. This can lead to very confusing errors. Sometimes the error messages don't even match the code in your sketch, since the error line is the "hidden" code inserted by the Arduino IDE.

My suspicion is this is the cause of your error. For some reason, the use of tabs is causing the prototype for your AnalogChannelRead function to be inserted in the preprocessed code before the declaration of the AnalogCHConfig type.

The workaround is to manually add the function prototype in the correct location in your sketch (after the declaration of the AnalogCHConfig type):

void AnalogChannelRead(AnalogCHConfig &Test);

When you encounter such an error, it can be very helpful to examine the post-sketch preprocessing output:

  • File > Preferences
  • Check the box next to "Show verbose output during: compilation'
  • Click "OK"
  • Sketch > Verify/Compile
  • After compilation fails, scroll the black console window at the bottom of the Arduino IDE window all the way to the top.
  • Examine the first line of output to find the value of the "-build-path" option.

For example, if you had this:

C:\ArduinoIDE\arduino-nightly\arduino-builder -dump-prefs -logger=machine -hardware C:\ArduinoIDE\arduino-nightly\hardware -hardware C:\Users\per\AppData\Local\Arduino15\packages -hardware E:\electronics\arduino\hardware -tools C:\ArduinoIDE\arduino-nightly\tools-builder -tools C:\ArduinoIDE\arduino-nightly\hardware\tools\avr -tools C:\Users\per\AppData\Local\Arduino15\packages -built-in-libraries C:\ArduinoIDE\arduino-nightly\libraries -libraries E:\electronics\arduino\libraries -fqbn=esp32:esp32:node32s:FlashFreq=80,UploadSpeed=921600 -vid-pid=0X2341_0X0042 -ide-version=10809 -build-path C:\Users\per\AppData\Local\Temp\arduino_build_889992 -warnings=all -build-cache C:\Users\per\AppData\Local\Temp\arduino_cache_764477 -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.esptool.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\esptool\2.3.1 -prefs=runtime.tools.esptool-2.3.1.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\esptool\2.3.1 -prefs=runtime.tools.mkspiffs.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\mkspiffs\0.2.3 -prefs=runtime.tools.mkspiffs-0.2.3.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\mkspiffs\0.2.3 -prefs=runtime.tools.xtensa-esp32-elf-gcc.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-80-g6c4433a-5.2.0 -prefs=runtime.tools.xtensa-esp32-elf-gcc-1.22.0-80-g6c4433a-5.2.0.path=C:\Users\per\AppData\Local\Arduino15\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-80-g6c4433a-5.2.0 -verbose C:\Users\per\AppData\Local\Temp\arduino_modified_sketch_19197\sketch_dec31a.ino

the temporary build folder is C:\Users\per\AppData\Local\Temp\arduino_build_889992.

Open the .ino.cpp file in the sketch subfolder of the temporary build folder with a text editor.

The temporary build folder will be deleted when you exit the Arduino IDE.

void AnalogChannelRead(AnalogCHConfig &Test)

"AnalogCHConfig" looks like a typedef or struct. where is it defined relative (before/after) "AnalogChannelRead"

I have stripped out most of my code sop I can focus on just this error.

Below is the temp file made when the compile is successful.

#include <Arduino.h>
#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\a_GLOBAL.ino"
//Start of TAB1 a_Global.ino

//Data structure for Analog channels
struct AnalogCHConfig {
  int LowerCali;
  int NeturalCali;
  int HighCali;
  byte LowEP;
  byte HighEP;
  int Trim;
  boolean Reversed;
};

//Define data structures
AnalogCHConfig CH1Config, CH2Config;

#line 17 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\a_GLOBAL.ino"
void AnalogChannelRead(AnalogCHConfig &Test);
#line 5 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
void setup();
#line 3 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\c_LOOP.ino"
void loop();
#line 8 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\e_RADIO.ino"
void send();
#line 17 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\a_GLOBAL.ino"
void AnalogChannelRead(AnalogCHConfig &Test)
{
  Test.LowerCali = 100;
  Test.HighCali  = 500;
}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
//Start of TAB2 b_SETUP.ino



void setup() {
  

}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\c_LOOP.ino"
//This file contains the main loop.

void loop() {

}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\d_EEPROM.ino"
////This file contains all the EEPROM configuration.



#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\e_RADIO.ino"



void send() {
}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\f_MAPPING.ino"
//This file contains all the custom mapping finctions.

and below is the code that produces an error.

#include <Arduino.h>
#line 3 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
void AnalogChannelRead(AnalogCHConfig &Test);
#line 9 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
void setup();
#line 3 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\c_LOOP.ino"
void loop();
#line 8 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\e_RADIO.ino"
void send();
#line 0 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\a_GLOBAL.ino"
//Start of TAB1 a_Global.ino

//Data structure for Analog channels
struct AnalogCHConfig {
  int LowerCali;
  int NeturalCali;
  int HighCali;
  byte LowEP;
  byte HighEP;
  int Trim;
  boolean Reversed;
};

//Define data structures
AnalogCHConfig CH1Config, CH2Config;

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\b_SETUP.ino"
//Start of TAB2 b_SETUP.ino

void AnalogChannelRead(AnalogCHConfig &Test)
{
  Test.LowerCali = 100;
  Test.HighCali  = 500;
}

void setup() {
  

}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\c_LOOP.ino"
//This file contains the main loop.

void loop() {
  //Wait for interval then send new data
//  currentMillis = millis();
//  if (currentMillis - prevMillis >= txIntervalMillis) {
//    if (Calibrated == true) {
//      send();
//    } else {
//      DEBUG_PRINTLN("Unit not calibrated");
//    }
//    
//  }
}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\d_EEPROM.ino"
////This file contains all the EEPROM configuration.



#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\e_RADIO.ino"
//This file contains the radio transmission/receive code.


void send() {
}

#line 1 "C:\\Users\\Fraser\\Documents\\Arduino\\GT3X_Pistol_V1\\a_GLOBAL\\f_MAPPING.ino"

The biggest difference looks to be where it puts the function declarations. It would appear that if there is a function in the first tab the rest of the function declarations get added to the code just before it but if there is no function in the first tab all the declarations are added to the beginning of the code.

I am assuming that the line

void AnalogChannelRead(AnalogCHConfig &Test);

being written before the struct is defined is then what is causing the error in the compiler.

What would be the best way to resolve the issue with how the Tabs are being handled?

Thanks.

GForce2010:
being written before the struct is defined is then what is causing the error in the compiler.

Correct.

GForce2010:
What would be the best way to resolve the issue with how the Tabs are being handled?

Manually add the function prototype in the correct location.

pert:
Correct.
Manually add the function prototype in the correct location.

Adding void AnalogChannelRead(AnalogCHConfig &Test); to the bottom of tab1 works.

On checking the temp file it adds all the auto generated deceleration to the top of the file but leaves out the AnalogChannelRead which now appears after the structs are setup.

Thanks for your help.

You're welcome. I'm glad to hear it's working now. Enjoy!
Per