Un .ino Arduino Sketch verrà compilato direttamente su GCC-AVR?


10

Ok, abbiamo visto tutte quelle domande sul web come Arduino vs C ++ o altre domande simili. E la stragrande maggioranza delle risposte non tocca nemmeno le differenze di compilazione se non attraverso informazioni astratte.

La mia domanda mira a risolvere le effettive differenze (non le preferenze) nel modo in cui un file .ino rinominato in un file .cpp o altra estensione simile per c ++ verrebbe compilato usando GCC-AVR. So che devi includere almeno il file di intestazione di Arduino, ma oltre a ciò, cosa causerebbe un errore di compilazione se la compilazione dicesse .ino al file .cpp usando, ad esempio, GCC-AVR. Per semplicità, usiamo il classico esempio di lampeggiamento per spiegare quali sono le differenze. Oppure, se hai uno snippet di codice migliore da utilizzare, ti preghiamo in ogni caso di includere lo snippet nella tua risposta e spiegare accuratamente le differenze.

Per favore, nessuna opinione su quale sia un modo o uno strumento migliore da usare.

FYI. Uso Platformio per lo sviluppo e noto un processo di conversione in corso dietro le quinte durante la compilazione. Sto cercando di capire cosa sta realmente accadendo lì, quindi quando scrivo in Arduino, capisco anche la versione "pura" di C ++.

Grazie per le risposte ponderate alla mia domanda in anticipo.


Stai chiedendo informazioni specifiche gccsul desktop o sul compilatore GCC for AVR avr-gcc? c'è una differenza molto più grande rispetto a quella tra a .inoe un .cppfile.
BrettAM

@BrettAM Il toolkit GCC-AVR come Arduino UNO è la scheda target e utilizza un chip Atmel AVR, come sono sicuro che tu sappia. Grazie per la chiamata all'ambiguità nella mia domanda. E sì, so che c'è una differenza molto più grande. Questo è il motivo per cui sto ponendo questa domanda. Per sapere quali sono queste differenze!
RedDogAlpha

Risposte:


14

Vedi la mia risposta qui: Classi e oggetti: quanti e quali tipi di file sono effettivamente necessari per usarli? - in particolare: come l'IDE organizza le cose .

So che devi almeno includere il file di intestazione di Arduino

Sì, dovresti farlo.

ma oltre a ciò, cosa causerebbe un errore di compilazione se la compilazione dicesse .ino al file .cpp usando, per esempio, GCC-AVR.

L'IDE genera prototipi di funzioni per te. Il codice in un file .ino può o meno averne bisogno (probabilmente lo farà a meno che l'autore non sia abbastanza disciplinato da programmare nel solito modo C ++ e farlo da solo).


Se lo "schizzo" contiene altri file (ad es. Altri file .ino, .c o .cpp), questi dovrebbero essere incorporati nel processo di compilazione come descrivo nella mia risposta menzionata sopra.

Inoltre dovresti (compilare e) collegare in tutte le librerie utilizzate dallo schizzo.


Non hai chiesto informazioni sul lato di collegamento delle cose, ma naturalmente i vari file, come compilati, devono essere collegati insieme, e quindi trasformati in un file .elf e .hex ai fini del caricamento. Vedi sotto.


Esempio di makefile

Sulla base dell'output IDE qualche tempo fa ho creato un semplice makefile :

#
# Simple Arduino Makefile
#
# Author: Nick Gammon
# Date: 18th March 2015

# where you installed the Arduino app
ARDUINO_DIR = C:/Documents and Settings/Nick/Desktop/arduino-1.0.6/

# various programs
CC = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-gcc"
CPP = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-g++"
AR = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-ar"
OBJ_COPY = "$(ARDUINO_DIR)hardware/tools/avr/bin/avr-objcopy"

MAIN_SKETCH = Blink.cpp

# compile flags for g++ and gcc

# may need to change these
F_CPU = 16000000
MCU = atmega328p

# compile flags
GENERAL_FLAGS = -c -g -Os -Wall -ffunction-sections -fdata-sections -mmcu=$(MCU) -DF_CPU=$(F_CPU)L -MMD -DUSB_VID=null -DUSB_PID=null -DARDUINO=106
CPP_FLAGS = $(GENERAL_FLAGS) -fno-exceptions
CC_FLAGS  = $(GENERAL_FLAGS)

# location of include files
INCLUDE_FILES = "-I$(ARDUINO_DIR)hardware/arduino/cores/arduino" "-I$(ARDUINO_DIR)hardware/arduino/variants/standard"

# library sources
LIBRARY_DIR = "$(ARDUINO_DIR)hardware/arduino/cores/arduino/"

build:

    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(MAIN_SKETCH) -o $(MAIN_SKETCH).o
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)avr-libc/malloc.c -o malloc.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)avr-libc/realloc.c -o realloc.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WInterrupts.c -o WInterrupts.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring.c -o wiring.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_analog.c -o wiring_analog.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_digital.c -o wiring_digital.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_pulse.c -o wiring_pulse.c.o 
    $(CC) $(CC_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)wiring_shift.c -o wiring_shift.c.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)CDC.cpp -o CDC.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)HardwareSerial.cpp -o HardwareSerial.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)HID.cpp -o HID.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)IPAddress.cpp -o IPAddress.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)main.cpp -o main.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)new.cpp -o new.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Print.cpp -o Print.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Stream.cpp -o Stream.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)Tone.cpp -o Tone.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)USBCore.cpp -o USBCore.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WMath.cpp -o WMath.cpp.o 
    $(CPP) $(CPP_FLAGS) $(INCLUDE_FILES) $(LIBRARY_DIR)WString.cpp -o WString.cpp.o 
    rm core.a
    $(AR) rcs core.a malloc.c.o 
    $(AR) rcs core.a realloc.c.o 
    $(AR) rcs core.a WInterrupts.c.o 
    $(AR) rcs core.a wiring.c.o 
    $(AR) rcs core.a wiring_analog.c.o 
    $(AR) rcs core.a wiring_digital.c.o 
    $(AR) rcs core.a wiring_pulse.c.o 
    $(AR) rcs core.a wiring_shift.c.o 
    $(AR) rcs core.a CDC.cpp.o 
    $(AR) rcs core.a HardwareSerial.cpp.o 
    $(AR) rcs core.a HID.cpp.o 
    $(AR) rcs core.a IPAddress.cpp.o 
    $(AR) rcs core.a main.cpp.o 
    $(AR) rcs core.a new.cpp.o 
    $(AR) rcs core.a Print.cpp.o 
    $(AR) rcs core.a Stream.cpp.o 
    $(AR) rcs core.a Tone.cpp.o 
    $(AR) rcs core.a USBCore.cpp.o 
    $(AR) rcs core.a WMath.cpp.o 
    $(AR) rcs core.a WString.cpp.o 
    $(CC) -Os -Wl,--gc-sections -mmcu=$(MCU) -o $(MAIN_SKETCH).elf $(MAIN_SKETCH).o core.a -lm 
    $(OBJ_COPY) -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 $(MAIN_SKETCH).elf $(MAIN_SKETCH).eep 
    $(OBJ_COPY) -O ihex -R .eeprom $(MAIN_SKETCH).elf $(MAIN_SKETCH).hex 

In quel caso particolare, il file .ino è stato compilato senza problemi dopo averlo rinominato in Blink.cpp e aggiunto questa riga:

#include <Arduino.h>

Grazie Nick per la tua concisa risposta, non sono vicino al livello che sei e non ho nemmeno pensato a un file di make. Quindi sostanzialmente la sintassi è la stessa, si tratta solo di collegare oggetti, giusto? Grazie per aver condiviso il tuo file make per consentirmi di analizzare. Sono sicuro che ci saranno altre domande che ne deriveranno! Grazie ancora!
RedDogAlpha

Il mio file sopra ha funzionato quando l'ho pubblicato, ma credo che potrebbe essere necessario modificare gli IDE successivi (perché si spostano o rinominano i file di libreria). Tuttavia, eseguire una compilazione dettagliata mostra ciò che l'IDE sta attualmente generando, che dovrebbe iniziare.
Nick Gammon

10

Vorrei solo aggiungere alcuni punti alla risposta di Nick Gammon:

  • Non è necessario rinominare un file .ino per compilarlo: se dici esplicitamente al compilatore che è C ++ (opzione -x c++), ignorerà l'estensione di file insolita e lo compilerà come C ++.
  • Non è necessario aggiungere #include <Arduino.h>il file .ino: puoi dire al compilatore di farlo per te ( -include Arduino.h).

Usando questi trucchi, posso compilare Blink.ino senza alcuna modifica , semplicemente invocando avr-g ++ con le opzioni appropriate della riga di comando:

avr-g++ -mmcu=atmega328p -DARDUINO=105 -DF_CPU=16000000L \
    -I/usr/share/arduino/hardware/arduino/cores/arduino \
    -I/usr/share/arduino/hardware/arduino/variants/standard \
    -Os -fno-exceptions -ffunction-sections -fdata-sections \
    -Wl,--gc-sections -g -Wall -Wextra \
    -x c++ -include Arduino.h \
    /usr/share/arduino/examples/01.Basics/Blink/Blink.ino \
    -x none /usr/local/lib/arduino/uno/libcore.a -lm \
    -o Blink.elf

Alcune note sulla riga di comando sopra:

  • /usr/local/lib/arduino/uno/libcore.aè dove ho salvato il core Arduino compilato. Odio ricompilare più e più volte le stesse cose.
  • -x noneè necessario per ricordare nuovamente al compilatore le estensioni dei file. Senza di esso, supporrebbe che libcore.a sia un file C ++.

Ho imparato quei trucchi da Arduino-Makefile del Sudar Muthu . Questo è un Makefile molto generale che funziona con molte schede e librerie. L'unica cosa che manca rispetto all'IDE di Arduino sono le dichiarazioni forward.


Molto bello, Edgar! La mia soluzione fondamentalmente imita ciò che fa l'IDE, la tua risolve il problema reale da gestire in modo molto più ordinato. Ovviamente dovresti fare il libcore.afile in anticipo. Suppongo che le righe nella mia risposta quale build core.apossano essere fatte in anticipo, quindi non devono far parte di ogni build. L'esperienza ha dimostrato che schizzi più complessi (ad es. Utilizzando Wire o SPI) necessitano di aggiungere più file core.a.
Nick Gammon

@NickGammon: Esatto, Makefile di Muthu (e, suppongo, l'IDE di Arduino) tende a mettere qualunque libreria che usi in libcore.a. Non mi piace molto questo approccio, poiché rende la presunta "libreria di base" dipendente dal particolare programma che compilate. Per le librerie a file singolo, come Wire o SPI, preferisco semplicemente inserire il file C ++ della libreria nello stesso comando di compilazione del programma principale. Quella riga di comando diventa facilmente abbastanza lunga, quindi uso un Makefile.
Edgar Bonet,

1
Una delle cose che mi piacciono dell'IDE è che non devi fare il furbo. Comunque, per progetti semplici "funziona".
Nick Gammon
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.