Spurious compilation error due to incorrect sketch preprocessing

This old feature is still present in Arduino IDE 2.3.10:

Target: ESP32S3 Dev Module, but I suspect other architectures are also affected:

#include <Arduino.h>
//extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv); {  // Uncomment me to fix the issue
extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv) {


  return 0;
}

void setup() {
  
  Serial.begin(115200);

}


void loop() {

  delay(1000);
}

Compiler output (line numbers are wrong because I removed comments from the source file before posting):

D:\Arduino\espshell\espshell.ino:56:18: error: conflicting declaration of 'void setup()' with 'C' linkage
   56 | void setup() {
      |                  ^    
In file included from D:\Arduino\espshell\espshell.ino:5:
C:\Users\WINDOWS\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.10\cores\esp32/Arduino.h:155:6: note: previous declaration with 'C++' linkage
  155 | void setup(void);
      |      ^~~~~
D:\Arduino\espshell\espshell.ino:63:18: error: conflicting declaration of 'void loop()' with 'C' linkage
   63 | void loop() {
      |                  ^   
C:\Users\WINDOWS\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.3.10\cores\esp32/Arduino.h:156:6: note: previous declaration with 'C++' linkage
  156 | void loop(void);
      |      ^~~~
exit status 1

This code is the real code. The function of interest is declared as weak symbol in another library, thats why it is declared in this way

Oh I forgot to post the autogenerated .ino.cpp

Enjoy:

#line 38 "D:\\Arduino\\espshell\\espshell.ino"
 extern "C" int cmd_misc_user(int _Argc, char **_Argv);
#line 56 "D:\\Arduino\\espshell\\espshell.ino"
 extern "C" void setup();
#line 63 "D:\\Arduino\\espshell\\espshell.ino"
 extern "C" void loop();
#line 38 "D:\\Arduino\\espshell\\espshell.ino"
extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv) {

This all can actually be fixed in one move: just add a checkbox to the IDE's preferences : "[*] Autogenerate function forward declarations", keep it ON by default.

I compiled the code for an Arduino Mega without issues. Compiling for the ESP32 shows indeed the issue.
I did compare the ino.cpp files for both scenarios and they are the same.
I also compiled for a Teensy 4.1 without problems; I did not compare the ino.cpp.

Sounds more like a compiler bug to me.

If you want to continue a discussion I suggest that you start a new topic.

PS
I could not find an ESP32S3 Dev Module in the list of supported boards, only a ESP32S3 Dev Module Octal (WROOM2) which I used for the test.

FQBN: esp32:esp32:esp32s3-octal

Do you mean they also have extern "C" setup(); but compile with no errors?

I happen to have esp32 board version 3.3.7 here

$ cd ~/.arduino15/packages/esp32/hardware/esp32/3.3.7/
$ sed -nE 's/.*\.name=(ESP32.+Dev Module)$/\1/p' boards.txt | LC_ALL=C sort
ESP32 Dev Module
ESP32C2 Dev Module
ESP32C3 Dev Module
ESP32C5 Dev Module
ESP32C6 Dev Module
ESP32C61 Dev Module
ESP32H2 Dev Module
ESP32P4 Dev Module
ESP32S2 Dev Module
ESP32S3 Dev Module

Listed, and not hidden

$ grep -B 1 'hide=true' boards.txt
esp32_family.name=ESP32 Family Device
esp32_family.hide=true
--
esp32c2.name=ESP32C2 Dev Module
esp32c2.hide=true
--
esp32c61.name=ESP32C61 Dev Module
esp32c61.hide=true

It's fifth in the menu in the IDE. Just plain ESP32 is 8th.

I forgot to mention, it's version 3.3.10.

I took your code; this is the ino.cpp generated for the Mega

#line 1 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
#include <Arduino.h>
//extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv); {  // Uncomment me to fix the issue
#line 3 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" int cmd_misc_user(int _Argc, char **_Argv);
#line 9 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" void setup();
#line 16 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" void loop();
#line 3 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv) {


  return 0;
}

void setup() {
  
  Serial.begin(115200);

}


void loop() {

  delay(1000);
}

Downgraded the ESP32 board package to 3.3.7 and selected the ESP32S3 Dev Module.
Generated ino.cpp (just so you can compare directly with the Mega's ino.cpp).

#line 1 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
#include <Arduino.h>
//extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv); {  // Uncomment me to fix the issue
#line 3 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" int cmd_misc_user(int _Argc, char **_Argv);
#line 9 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" void setup();
#line 16 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
 extern "C" void loop();
#line 3 "C:\\Users\\bugge\\OneDrive\\Documents\\Arduino\\1_forum.arduino.cc\\1447778\\1447778.post22\\1447778.post22.ino"
extern "C" __attribute__((used)) int cmd_misc_user(int _Argc, char **_Argv) {


  return 0;
}

void setup() {
  
  Serial.begin(115200);

}


void loop() {

  delay(1000);
}

So it is wrong. I mean your generated code for mega is wrong. Arduino has added extern "C" to C++ functions loop() and setup()

Just as I expected - other architectures are also affected. Since it affects more tham one Arch it should be reported I think

Must not be like that. setup() has C++ linkage.

Since the discussion is tangential to the subject of the original topic, I split this interesting and valuable conversation off to a dedicated forum topic.

Please carry on with discussion of the sketch preprocessor problem here.

Discussion on other subjects directly related to the Arduino IDE 2.3.10 release announcement can be conducted in the other topic.

Thanks for your report @vvb333007. The Arduino developers are tracking the bug here:

Opened: 2022, Imperfection :-). No way they going to fix it. Imperfections are low-prio things :).

Hi vvb333007, you've touched on a crucial point. The IDE and its preprocessor sometimes create issues like yours because they hide what's happening "under the hood."

This is exactly why I created avr-compiler-js ( GitHub - costycnc/avr-compiler-js: A fully online tool, no installation needed. · GitHub ). It's not "better" or "worse" than the IDE. It's different. It's an approach I call "The Wooden Toy Philosophy" :

For an absolute beginner:

  • No installation: open your browser and type sbi 5,5 → the D13 LED turns on.
  • No pinMode(), no setup(), no loop().
  • You immediately see that pin D13 is "connector 5 of box 5" (PORTB, bit 5). You understand it with your eyes, not with abstractions.

For your specific problem:
In my tool, there is no preprocessor rewriting your code. What you write is exactly what the compiler sees. So errors like yours cannot happen. It's pure Assembly , no magic.

The key point I want to make (and this answers your original question, vvb333007):
Your error happens because the IDE tries to "help" you but ends up confusing you. My experience with CostyCNC taught me that:

  1. First, you let beginners touch the registers directly (SBI 5,5, CBI 5,5, OUT, IN...)
  2. Then, once they understand that a register is just a set of ON/OFF switches, they can use abstractions like digitalWrite().

If a beginner starts with digitalWrite(), "pin 13" is just magic words to them. If they start with sbi 5,5, they understand that pin D13 is bit 5 of PORTB register. A switch. No magic.

Practical conclusion :

Try writing your code like this (without any preprocessor interference):

// No #include <Arduino.h>
// No forced setup/loop

void setup(void) {
    // Your code here
}

void loop(void) {
    // Your code here
}

Compile it with avr-compiler-js or with avr-gcc from the command line. You'll see the conflicting declaration error disappears because no one is rewriting your code behind your back.

My invitation to everyone: Don't be afraid to open the "hood" of the car. AVR registers aren't difficult. They're just lots of tiny switches. And sbi 5,5 is the key to turning on the light inside the engine.

P.S. I keep some notes and examples at costycnc.it/avr1

Happy coding to all!

I am afraid that you are looking at things from a position os knowledge. When you say

how does the beginner know that pin 13 is bit 5 or PORTB ?
What is sbi ?
Which of the 5's relates to the bit number and what does the other 5 mean ?
Where is the relationship between PORTB and pin 13 established ?

You jumped to a false conclusion. The "type: imperfection" label identifies items related to any defect whatsoever. The name was intentionally chosen to be applicable to any component of the project, at any severity on the spectrum from "missing comma in the readme" to "Skynet is waging war on humanity".

The label does not in any way indicate level of priority. We have a separate set of "priority" labels for that purpose. "priority" labels are assigned by a manager during the planning process, while "type" labels are assigned by a maintainer during triage.

This labeling schema was developed based on over a decade of maintaining the issue trackers of hundreds of open source repositories.

I am a maintainer, so I assigned the issue the appropriate "type: imperfection" label. I am not a manager of the Arduino CLI project, so I am not in a role to assign priority to the issue.

i did , the mcu have registers and bit not portb and pb5, when write asm you touch wires.

That is exactly the point.

Of course, this approach is purely educational. It is not meant for writing massive or intensive production code. It is strictly for learning.

Starting with online tools, without installing anything and just writing sbi 5,5 without even knowing how to program, takes only 10 minutes. A beginner types it, the LED turns on, and they immediately understand the physical connection. No magic.

Compare this to the traditional Arduino way:

  1. You must download and install a heavy IDE.
  2. You must learn C syntax before doing anything.
  3. Beginners just copy and paste the "Blink" sketch.

This gives them the fake impression that they are programmers, but they actually understand nothing about what is happening under the hood.

Touching the raw registers directly removes the fake magic. It teaches the real hardware from minute one.

Let's try not to derail the topic with posts that are irrelevant to the topic.

I am willing to bet they don't
Here they are with a Uno 3 board with a pin labelled 13. A beginner writes a HIGH value to pin 13 and the LED turns on. Simple

Do they need to know or care about ports and bits in ports ? No, of course not

This is my last word on the subject in this topic for the reason suggested by @sterretje but I could not let your contentious post go without commenting

You can work around the errors by moving the offending code to separate header and cpp files.