Skip to content

fix(ino): generated prototypes are inserted above the sketch's own #includes and type definitions #1196

Closed

Description

@zackees

Split out of #1076 (flagged in the ".ino.prelude.h direction update" comment as worth its own child issue — it affects real builds today, IDE aside).

Problem

preprocess_ino_files (crates/fbuild-build-engine/src/source_scanner.rs, prototype block emitted before the concatenated sketch text) writes all auto-generated function prototypes above the user's own #includes and type definitions. A sketch that defines a type and then a function taking it:

#include "helpers.h"
struct MyStruct { int x; };
void draw(MyStruct s) { /* ... */ }

gets void draw(MyStruct s); emitted before struct MyStruct exists → compile error in the generated .ino.cpp.

arduino-cli avoids this by inserting prototypes after the include block. Note the interaction with #1076's prelude design: the IDE prelude header is currently defined as the machine-written top half (Arduino.h + prototypes) -include'd ahead of the raw .ino — moving prototypes below the include block changes what the prelude can contain for affected sketches, so the fix needs to keep the build artifact and the IDE prelude in agreement (editor and compiler must keep seeing identical translation units).

Acceptance

  • A sketch with a user-defined type used in a later function's signature compiles (prototype lands after the declarations it needs, matching arduino-cli placement).
  • The IDE-flavored compile DB / prelude stays in parity: clangd --check=<sketch.ino> reports the same diagnostics as compiling the generated .ino.cpp.
  • Regression tests for both single-tab and multi-tab layouts.

Parent: #1076 (Phase 0 follow-up).

Activity

  1. zackees commented on Jul 27, 2026

    @zackees
    MemberAuthor

    Research update — revising the drafted acceptance criteria before implementing.

    The original acceptance said to match arduino-cli's placement (prototypes after the include block). Verified against arduino-cli upstream: arduino-cli does not solve this class — prototypes referencing sketch-defined types still land before the type declaration there too, producing spurious compile failures that remain open bugs (arduino-cli#2161, arduino-cli#2977, related #2931/#1800), with "move the type to a .h file or add a manual prototype" as the documented workaround. Matching their placement would import their bug class, and any placement below the sketch's own leading code breaks the #1076 prelude design's load-bearing invariant (the machine-written text must be a pure prefix so -x c++ -include <prelude> + the raw .ino reproduces the exact build translation unit for clangd).

    Chosen approach instead: keep prototype insertion at the top (prelude prefix-property and editor/build parity untouched), and skip generating any prototype whose signature references a sketch-defined type (struct/class/enum/union/typedef/using names declared in the concatenated sketch text — detected with the existing tree-sitter parse). Result:

    • the guaranteed-broken output becomes valid standard C++ — affected functions simply follow declare-before-use, which is exactly the ecosystem's documented workaround, minus the error;
    • sketches using builtin/Arduino types keep full use-before-definition behavior;
    • editor and compiler keep seeing byte-identical translation units (clangd --check parity holds by construction);
    • strictly better than arduino-cli, which emits the broken prototype.

    Revised acceptance:

    • A sketch defining a type and a later function taking/returning it compiles (no auto-prototype emitted for that function).
    • Functions with builtin/Arduino-typed signatures keep their auto-prototypes (use-before-definition still works).
    • Prelude/IDE parity preserved (same machine prefix in .ino.cpp and <stem>.ino.prelude.h).
    • Regression tests for single-tab and multi-tab layouts, including a mixed sketch (one skippable + one prototypable function).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions