arduino-cli
arduino-cli copied to clipboard
Generated prototype incorrectly prefixed with `extern "C"` when using `extern "C" { ... }` to mix C functions in an `.ino` file.
Describe the problem
Compiling the following blink sketch for ESP32 board:
#ifdef __cplusplus
extern "C"
{
#endif
void dummy(void) {}
#ifdef __cplusplus
}
#endif
void setup()
{
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
results in errors:
sketch_esp32_blink:12:12: error: conflicting declaration of 'void setup()' with 'C' linkage
void setup()
^
In file included from /tmp/arduino_build_620310/sketch/sketch_esp32_blink.ino.cpp:1:0:
.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:118:6: note: previous declaration with 'C++' linkage
void setup(void);
^
sketch_esp32_blink:17:11: error: conflicting declaration of 'void loop()' with 'C' linkage
void loop()
^
In file included from /tmp/arduino_build_620310/sketch/sketch_esp32_blink.ino.cpp:1:0:
.arduino15/packages/esp32/hardware/esp32/1.0.6/cores/esp32/Arduino.h:119:6: note: previous declaration with 'C++' linkage
void loop(void);
^
exit status 1
conflicting declaration of 'void setup()' with 'C' linkage
Arduino CLI version
Original report
Arduino IDE 1.8.19
Last verified with
60c1c98
Operating system
- Linux
- Windows
Operating system version
- Ubuntu 21.10
- Windows 11
Additional context
If the extern "C" { ... } block does not define any function but only variables, or if the whole extern "C" { ... } block is moved after the definition of setup and loop functions, the code compiles successfully.
If the extern "C" { ... } block only declares functions, and functions are defined in a separate module (file), everything compiles correctly.
The files with .cpp extensions do not have this problem, and allow mixing C linkage functions defined within extern "C" { ... } blocks.
Looks like, when the compiler encounters a C linkage function definition in a sketch file (.ino extension), it assumes that the rest of file defines only C linkage functions.
The error can not be reproduced when compiling for boards using AVR or ARM processors that I could test with.
Related
- https://github.com/arduino/arduino-cli/issues/1591
Issue checklist
- [X] I searched for previous reports in the issue tracker
- [X] I verified the problem still occurs when using the nightly build
- [X] My report contains all necessary details
Thanks @dmalenic
In case it will be useful to the developers, I'll provide a minimal demo of the bug:
$ arduino-cli version
arduino-cli.exe Version: nightly-20220110 Commit: 60c1c98 Date: 2022-01-10T01:28:45Z
$ SKETCH_PATH="/tmp/ExternCBug"
$ mkdir "$SKETCH_PATH"
$ echo "#ifdef __cplusplus
extern \"C\" {
#endif
void dummy(void) {}
#ifdef __cplusplus
}
#endif
void setup() {}
void loop() {}
" > "$SKETCH_PATH"/ExternCBug.ino
$ arduino-cli compile --fqbn arduino:avr:uno --preprocess "$SKETCH_PATH"
#include <Arduino.h>
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\ExternCBug\\ExternCBug.ino"
#ifdef __cplusplus
extern "C" {
#endif
#line 4 "C:\\Users\\per\\AppData\\Local\\Temp\\ExternCBug\\ExternCBug.ino"
extern "C" void dummy(void);
#line 8 "C:\\Users\\per\\AppData\\Local\\Temp\\ExternCBug\\ExternCBug.ino"
void setup();
#line 9 "C:\\Users\\per\\AppData\\Local\\Temp\\ExternCBug\\ExternCBug.ino"
void loop();
#line 4 "C:\\Users\\per\\AppData\\Local\\Temp\\ExternCBug\\ExternCBug.ino"
void dummy(void) {}
#ifdef __cplusplus
}
#endif
void setup() {}
void loop() {}
Vaguely related to https://github.com/arduino/arduino-cli/issues/1591
I think this is another case where the automatic prototype generation that arduino-cli does cannot cope with more complicated sketches. What I suspect happens, is that a prototype is generated for the loop() and setup() functions. IIRC prototypes are inserted directly before the first other function definition or declaration found in the .ino file (so they can end up after any initial type declarations when those are before all functions). In this case, that puts the prototypes inside the extern "C" blocks, which leads to conflicting declarations.
I'm not sure, but I suspect that this is going to be hard to fix (certainly with the ctags-based approached, but even for the clang-based parsing approach this probably needs some special casing). Also, if you're working with external C functions like this, chances are you're already a more advanced that does not really need the auto-generated prototypes at all.
Here's some things you could do/try to get your code working right now:
- Add explicit forward declarations for all your functions (setup/loop in this example, probably also dummy), that should prevent them from begin autogenerated.
- Use extern as part of the declaration (e.g.
extern "C" void dummy(void) {}) rather than a block. Note that .ino files are always compiled as C++, so you do not need the#ifdef __cplusplushere (those are needed in .h files that might be included from C or C++ code). - Put your code in .cpp files (and maybe declarations in .h files) like you would do outside of the Arduino IDE. You still need a .ino file, but it can just be empty (or still contain some of the code).
I've updated the issue title, as this is not an ESP32-specific issue.
Additional observation, that might be helpful. My original report was Arduino IDE specific, and within Arduino IDE the problem is limited to ESP32 boards (don't have ESP 8266 board to test). As @per1234 showed, if arduino-cli is used the bug is not ESP32 specific.
I just tried script @per1234 provided and it breaks. But If I load the sketch his script created /tmp/ExternCBug/ExternCBug.ino to Arduino IDE, and select target Arduino UNO (as in @per1234 example), it compiles and loads to the UNO board, as well as on MEGA 2560, Nano Every, DUE, MKR Vidor 4000, MKR WiFi 1010, Raspberry Pi Pico and Teensy 4.1. I tried arduino-cli on all those platforms (except Teensy) and it breaks on all of them exactly as @per1234 noticed.
Hopefully this observation helps, at least with resolving the arduino-cli problem for AVR and ARM boards. Maybe there are two separate but related issues - one with IDE and one with CLI.