Skip to content
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

Treatment of multi-file sketches not match Arduino build process #130

Closed
twpayne opened this issue Mar 21, 2015 · 11 comments
Closed

Treatment of multi-file sketches not match Arduino build process #130

twpayne opened this issue Mar 21, 2015 · 11 comments
Assignees
Milestone

Comments

@twpayne
Copy link
Contributor

twpayne commented Mar 21, 2015

Background: I'm porting an existing multi-file Arduino sketch to PlatformIO. It does not currently work because PlatformIO's conversion of multi-file sketches to C++ is different to the Arduino IDE's.

The Arduino IDE's process is described in the Arduino Build Process, section "Multi-file sketches" and "Transformations to the main sketch file".

PlatformIO's conversion is in ConvertInoToCpp.

Notable differences are:

  • Arduino creates a single output source file containing all input .ino files, whereas PlatformIO creates one per .ino file.
  • Arduino inserts forward function declarations into the single resulting sketch file, whereas PlatformIO only inserts per-file forward function declarations in each file.

Would you like a patch to change PlatformIO's behaviour to more closely match Arduino's?

@ivankravets
Copy link
Member

Could you provide me an example which works in Arduino IDE, but doesn't work in PlatformIO?

@twpayne
Copy link
Contributor Author

twpayne commented Mar 21, 2015

Here's a short example that demonstrates a difference. There are two source files:

src/Blink.io

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

src/PlatformIO_example.ino

/*
  Blink
  Turns on an LED on for one second, then off for one second, repeatedly.

  This example code is in the public domain.
 */

// Pin 13 has an LED connected on most Arduino boards.
// Pin 11 has the LED on Teensy 2.0
// Pin 6  has the LED on Teensy++ 2.0
// Pin 13 has the LED on Teensy 3.0
// give it a name:
int led = 13;

// the setup routine runs once when you press reset:
void setup() {
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);
}

// the loop routine runs over and over again forever:
void loop() {
  blink();
}

The Arduino compiles and builds this just fine, but PlatformIO gives an error:

$ platformio run
[Sat Mar 21 15:58:51 2015] Processing autogen_megaADK (platform: atmelavr, board: megaADK, framework: arduino)
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
avr-g++ -o .pioenvs/autogen_megaADK/src/Blink.o -c -fno-exceptions -fno-threadsafe-statics -g -Os -Wall -ffunction-sections -fdata-sections -MMD -mmcu=atmega2560 -DF_CPU=16000000L -DARDUINO_ARCH_AVR -DARDUINO_AVR_ADK -DARDUINO=10601 -DPLATFORMIO=010200 -I.pioenvs/autogen_megaADK/FrameworkArduino -I.pioenvs/autogen_megaADK/FrameworkArduinoVariant .pioenvs/autogen_megaADK/src/Blink.cpp
Blink.ino: In function 'void blink()':
Blink.ino:2:16: error: 'led' was not declared in this scope
scons: *** [.pioenvs/autogen_megaADK/src/Blink.o] Error 1
=========================================================================================================================== [ ERROR ] Took 0.54 seconds ===========================================================================================================================

The problem here is PlatformIO compiles src/Blink.ino on its own, which does not include a declaration of the variable led. The Arduino concatenates all the *.ino files together so the declaration for led appears in the same file as its use in the blink() function.

I'm not suggesting for a moment that this is a nice way to organise code, but I suspect that people would expect PlatformIO to behave the same way as the Arduino IDE.

Do tell me if you need any more info. I'm working on a very rough prototype to emulate the Arduino IDE's concatenation step at the moment.

@ivankravets
Copy link
Member

Thanks, I got you. I will resolve this issue today and ask you to test!

@twpayne
Copy link
Contributor Author

twpayne commented Mar 21, 2015

Thanks! Here's the rough-and-ready standalone script that seems to Do The Right Thing(tm):
https://gist.github.com/twpayne/bdea90725d3d9b6bba1c

@ivankravets
Copy link
Member

Tom, thanks for your script. However, this issue is more interesting:

  • need to detect which *.ino/pde candidate to be nominated as "main"
  • need to specify preprocessor with correct lines for multi-sketches. Warnings/Errors should be reported with correct lines from original sketches ,even when they are merged into single piomain.cpp.

See how I've fixed it 7f43df4


Could I ask you to test it using PlatformIO Development version?

@glynhudson
Copy link

Nice work guys. I'm running latest V2.9.4, should this fix be included?

I'm trying to migrate an existing project with multiple .ino files to platformio:
https://github.com/openenergymonitor/emonpi/tree/master/firmware/firmware

There are 6 files, I have renamed firmware.ino to main.ino to help to the platoformio compiler. however I am getting 'not defined' errors:

e.g. emonPi_startup function cannot be found which is in startup.ino.

These files compile fine with Arduino IDE 1.6.8. What can I do to make these files compile on platfomio? I would very much like to switch to using platormio, it's super nice. Good work 👍

~/Downloads/dev/platformio_test$ platformio run
[Tue Jun  7 13:37:33 2016] Processing uno (platform: atmelavr, board: uno, framework: arduino)
--------------------------------------------------------------------------------------------------------------------------------------------
avr-g++ -o .pioenvs/uno/src/tmp_ino_to.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -DPLATFORMIO=020904 -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant -I.pioenvs/uno/JeeLib_ID252 -I.pioenvs/uno/EmonLib_ID116 -I.pioenvs/uno/OneWire_ID1 -I.pioenvs/uno/DallasTemperature_ID54 -I.pioenvs/uno/Wire -I.pioenvs/uno/Wire/utility -I.pioenvs/uno/LiquidCrystal_I2C_ID576 -Isrc src/tmp_ino_to.cpp
avr-ar rcs .pioenvs/uno/libFrameworkArduinoVariant.a
avr-ranlib .pioenvs/uno/libFrameworkArduinoVariant.a
avr-g++ -o .pioenvs/uno/FrameworkArduino/CDC.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant .pioenvs/uno/FrameworkArduino/CDC.cpp
avr-g++ -o .pioenvs/uno/FrameworkArduino/HardwareSerial.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant .pioenvs/uno/FrameworkArduino/HardwareSerial.cpp
/home/glyn/Downloads/dev/platformio_test/src/main.ino: In function 'void setup()':
/home/glyn/Downloads/dev/platformio_test/src/main.ino:186:18: error: 'emonPi_startup' was not declared in this scope
if (RF_STATUS==1) RF_Setup();
^
/home/glyn/Downloads/dev/platformio_test/src/main.ino:188:40: error: 'check_for_DS18B20' was not declared in this scope
emonPi_LCD_Startup();
^
/home/glyn/Downloads/dev/platformio_test/src/main.ino:188:8: warning: unused variable 'numSensors' [-Wunused-variable]
emonPi_LCD_Startup();
^
/home/glyn/Downloads/dev/platformio_test/src/main.ino: In function 'void loop()':
/home/glyn/Downloads/dev/platformio_test/src/main.ino:316:24: error: 'send_emonpi_serial' was not declared in this scope

^
/home/glyn/Downloads/dev/platformio_test/src/rf.ino: In function 'void handleInput(char)':
/home/glyn/Downloads/dev/platformio_test/src/rf.ino:134:60: warning: value computed is not used [-Wunused-value]
-     Serial.print((char) ('@' + (nodeID & RF12_HDR_MASK)));
^
/home/glyn/Downloads/dev/platformio_test/src/rf.ino:135:28: warning: value computed is not used [-Wunused-value]
-     Serial.print(F(" i"));
^
/home/glyn/Downloads/dev/platformio_test/src/rf.ino: In function 'boolean RF_Rx_Handle()':
/home/glyn/Downloads/dev/platformio_test/src/rf.ino:51:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
/home/glyn/Downloads/dev/platformio_test/src/temperature.ino: In function 'int get_temperature(byte)':
/home/glyn/Downloads/dev/platformio_test/src/temperature.ino:28:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
avr-g++ -o .pioenvs/uno/FrameworkArduino/HardwareSerial0.o -c -fno-exceptions -fno-threadsafe-statics -std=gnu++11 -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO_ARCH_AVR -DARDUINO_AVR_UNO -DARDUINO=10608 -I.pioenvs/uno/FrameworkArduino -I.pioenvs/uno/FrameworkArduinoVariant .pioenvs/uno/FrameworkArduino/HardwareSerial0.cpp
scons: *** [.pioenvs/uno/src/tmp_ino_to.o] Error 1

@valeros
Copy link
Member

valeros commented Jun 7, 2016

Hi @twpayne
The simplest workaround is to add needed function declarations to firmware.ino right before includes, something like that:

extern void emonPi_startup();
extern void send_emonpi_serial();  
extern byte check_for_DS18B20(); 

#include <JeeLib.h>

@glynhudson
Copy link

Thanks, that did the trick 👍

@ivankravets
Copy link
Member

@glynhudson This is a bug. Please open a separate issue.

@ivankravets
Copy link
Member

@glynhudson I've just looked into this issue and found the problem. Please place comments for the prototypes above the declaration. For example, please replace https://github.com/openenergymonitor/emonpi/blob/master/firmware/firmware/startup.ino#L2 to

//Used in emonPi startup to detect presence of AC wavefrom and estimate VRMS voltage
double calc_rms(int pin, int samples) {

PlatformIO ino to cpp coverter doesn't touch comments from the files while Arduino IDE does.

@glynhudson
Copy link

Nice, this did the trick 👍

Thanks a lot, I have now migrated my project to platformio, with travisCI build testing :-D

https://github.com/openenergymonitor/emonpi/tree/master/firmware

costyn added a commit to costyn/LEDswarm that referenced this issue Jun 15, 2017
Added header file. Renamed to .ino because PlatformIO will then work
with multiple files
(platformio/platformio-core#130)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants