Skip to content

Generated prototype incorrectly prefixed with extern "C" when using extern "C" { ... } to mix C functions in an .ino file. #1618

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
3 tasks done
dmalenic opened this issue Jan 8, 2022 · 4 comments
Assignees
Labels
topic: build-process Related to the sketch build process topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project

Comments

@dmalenic
Copy link

dmalenic commented Jan 8, 2022

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

Issue checklist

  • I searched for previous reports in the issue tracker
  • I verified the problem still occurs when using the nightly build
  • My report contains all necessary details
@per1234 per1234 transferred this issue from arduino/Arduino Jan 10, 2022
@per1234
Copy link
Contributor

per1234 commented Jan 10, 2022

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 #1591

@per1234 per1234 added topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project labels Jan 10, 2022
@matthijskooijman
Copy link
Collaborator

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 __cplusplus here (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).

@matthijskooijman matthijskooijman changed the title ESP32 boards: compilation error when using extern "C" { ... } to mix C functions in an .ino file. Compilation error when using extern "C" { ... } to mix C functions in an .ino file. Jan 10, 2022
@matthijskooijman
Copy link
Collaborator

I've updated the issue title, as this is not an ESP32-specific issue.

@dmalenic
Copy link
Author

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.

@umbynos umbynos added the topic: build-process Related to the sketch build process label Feb 2, 2023
@per1234 per1234 changed the title Compilation error when using extern "C" { ... } to mix C functions in an .ino file. Generated prototype incorrectly prefixed with extern "C" when using extern "C" { ... } to mix C functions in an .ino file. Sep 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: build-process Related to the sketch build process topic: code Related to content of the project itself type: imperfection Perceived defect in any part of project
Projects
None yet
Development

No branches or pull requests

5 participants