arduino / arduino-preprocessor

Parses an Arduino Sketch and converts it into valid C++ source code
49 stars 13 forks source link

[arduino-PR-beta1.9-BUILD-44] prototype generation issue causes error ("works" on 1.8.5) #14

Open bperrybap opened 6 years ago

bperrybap commented 6 years ago

I don't know how prototypes are currently being generated but there is a difference in 1.9.0 vs 1.8.5

1.9.0 appears to be generating prototypes differently than 1.8.5 which can cause compilation errors. While 1.8.5 also has an issue with certain types of prototype generation & insertion, it appears that the way 1.8.5 generated prototypes, it got lucky and still allowed the compilation to succeed.

In 1.9.0 the new way of generating a prototype can generates a warning with the avr gcc compiler tools but cause a compilation error on the other cores like Arduino SAM, esp8266, and chipkit

My test environment was 32bit and 64 bit linux using the latest 1.9.0 build: arduino-PR-beta1.9-BUILD-44

Due to what is happening, the error output in the IDE is confusing since it reports an error in the source code (because the insertion inserted #line pointing to the function definition) but the actual error is on a hidden line of source code in the .cpp file generated by the IDE.

It appears that when the IDE decides to generate prototypes, it generates prototypes for all functions including functions that may already have had a prototype in the sketch. This is the actual issue and this issue is also an issue in 1.8.5; however, 1.8.5 was luckily getting away with it. But now 1.9.0 is using a slightly different way to generate the prototype which causes a compilation error.

This new compilation error issue shows up when the prototype declaration in the sketch is declaring a function with a default argument.

Here a minimal example that can demonstrate the issue:

void xmsg(const char *msg, int pause = 500);

void setup(void)
{
    Serial.begin(9600);
    ffoo(42);
}

void loop(void)
{
    xmsg("hello");
}

void xmsg(const char *msg, int pause)
{
    Serial.println(msg);
    delay(pause);
}

void ffoo(int x)
{
    Serial.println(x);
}

The 1.8.5 IDE will generate and insert a prototype that matches the function definition: void xmsg(const char *msg, int pause);

The 1.9.0 IDE will generate a prototype that matches the prototype that was declared in the sketch: void xmsg(const char *msg, int pause = 500);

This means that the .cpp file generated now contains two prototypes for the function. In the 1.8.5 IDE the IDE generated and inserted prototype (without the default argument) ends up being harmless and the compile will still work.

In the 1.9.0 IDE the IDE generated and inserted prototype with the default argument is a duplicate prototype. The avr compiler issues a warning for this but will allow the code to compile. The compilers for the the other cores do not like this and consider it an error.

Is there anyway for the IDE (builder or whoever does the prototype insertion) to be smart enough to not insert a prototype into the .cpp file that is already in the sketch?

facchinm commented 6 years ago

Hi @bperrybap , the builder in 1.9.0 uses arduino-preprocessor to generate the prototypes; while incredibly more powerful, there are still some rough edges. I'll add a test on https://github.com/arduino/arduino-builder/pull/250 (the binaries for 1.9.0 are generated from that code) to automatically check for this kind of construct.

bperrybap commented 6 years ago

Maybe it could do a final pass and remove any exact duplicates?

Is there anyway to do anything inside a sketch to force arduino-preprocessor to not generate any prototypes?