Description
Describe the problem
In order to make it easier for beginners to get started with writing Arduino sketches, and for the convenience of all users, Arduino CLI automatically generates and adds prototypes for functions defined in a .ino
file of a sketch.
Arduino sketches may consist of multiple .ino
files. This is useful because it allows large sketches to be split up to facilitate navigation of the codebase. These files are concatenated into a single file during sketch preprocessing. We expect that a sketch consisting of multiple .ino
files will be functionally identical to a sketch that contains the same code in a single .ino
file in the same order as the multi-file concatenation order.
🐛 Arduino CLI chooses an incorrect point to inject the generated function prototype under the following conditions:
- The sketch contains a function with a parameter of a custom type defined in the sketch.
- The function that depends on the custom type definition is in a supplemental
.ino
file. - The primary
.ino
file does not contain any function definitions.
This causes compilation to fail with a cryptic error.
To reproduce
$ arduino-cli version
arduino-cli Version: git-snapshot Commit: 20c9dd446 Date: 2025-07-09T02:51:31Z
$ mkdir -p "/tmp/FooSketch"
$ echo '
enum foo_t {};
void bar(foo_t baz) {
(void)baz; // Fix "unused parameter" warning
}
void setup() {}
void loop() {}
' > "/tmp/FooSketch/FooSketch.ino"
$ arduino-cli compile --fqbn arduino:avr:uno "/tmp/FooSketch"
Sketch uses 444 bytes (1%) of program storage space. Maximum is 32256 bytes.
Global variables use 9 bytes (0%) of dynamic memory, leaving 2039 bytes for local variables. Maximum is 2048 bytes.
🙂 The sketch compiles successfully because the void bar(foo_t baz)
prototype was correctly injected after the definition of the foo_t
type.
$ echo '
enum foo_t {};
' > "/tmp/FooSketch/FooSketch.ino"
$ echo '
void bar(foo_t baz) {
(void)baz; // Fix "unused parameter" warning
}
void setup() {}
void loop() {}
' > "/tmp/FooSketch/Supplemental.ino"
$ arduino-cli compile --fqbn arduino:avr:uno "/tmp/FooSketch"
C:\Users\per\AppData\Local\Temp\FooSketch\Supplemental.ino:2:10: error: variable or field 'bar' declared void
void bar(foo_t baz) {
^~~~~
C:\Users\per\AppData\Local\Temp\FooSketch\Supplemental.ino:2:10: error: 'foo_t' was not declared in this scope
[...]
$ arduino-cli compile --fqbn arduino:avr:uno --preprocess "/tmp/FooSketch"
#include <Arduino.h>
#line 2 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\Supplemental.ino"
void bar(foo_t baz);
#line 5 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\Supplemental.ino"
void setup();
#line 6 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\Supplemental.ino"
void loop();
#line 0 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\Supplemental.ino"
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\FooSketch.ino"
enum foo_t {};
#line 1 "C:\\Users\\per\\AppData\\Local\\Temp\\FooSketch\\Supplemental.ino"
void bar(foo_t baz) {
(void)baz; // Fix "unused parameter" warning
}
void setup() {}
void loop() {}
🐛 The compilation failed because the void bar(foo_t baz)
prototype was correctly injected before the definition of the foo_t
type.
Expected behavior
The system that is able to inject the prototype at the correct position in a single file sketch also works for the same code in a multi-file sketch.
Arduino CLI version
Operating system
Windows
Operating system version
11
Additional context
There is another report of prototype injection before its type declaration dependency at #2696. However, the conditions under which this occurs are fairly distinct from the conditions under which #2696 occurs, so it is not clear to me whether they are both caused by the same bug.
Originally reported by @sterretjeToo at https://forum.arduino.cc/t/tabbed-sketches-suggestion-or-how-to/1393854/32
Workaround
Manually add a function prototype at the appropriate location:
enum foo_t {};
void bar(foo_t baz); // Manually added function prototype to work around prototype generator bug.
Related
- Compilation fails due to function reordering #500
- ) in comment breaks function prototype generation #1253
- Generated prototype incorrectly prefixed with
extern "C"
when comment contains//
#1591 - Generated prototype incorrectly prefixed with
extern "C"
when usingextern "C" { ... }
to mix C functions in an.ino
file. #1618 - Backslash incorrectly inserted into generated prototype for multiline template function #1785
- No generated prototype for function with multi-line parameters in unsaved sketch #1800
- Emit a warning if a prototype is not generated due to known limitations #1944
- Prototype incorrectly generated for struct member function under certain conditions #2161
- Generated function prototype injected before declaration of custom parameter type #2696
- Prototype not generated for function with inline attribute #2697
- Prototype injected inside function definition when there is a line break after type #2931
- Generated prototypes are added after global variable declarations arduino-builder#85
- Prototype Generation With Typedef'd Types arduino-builder#298
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