.ino Arduino SketchはGCC-AVRで直接コンパイルできますか?


10

さて、ArduinoとC ++やその他の同様の質問など、ウェブ全体でこれらの質問を見てきました。また、回答の大部分は、抽象化された情報以外の方法ではコンパイルの違いにさえ触れません。

私の質問は、.cppファイルまたは他の同様のc ++ファイル拡張子に変更された.inoファイルがGCC-AVRを使用してコンパイルされる方法の(設定ではなく)実際の違いを解決することを目的としています。少なくともArduinoヘッダーファイルを含める必要があることはわかっていますが、それ以上に、たとえばGCC-AVRなどを使用して.inoを.cppファイルにコンパイルすると、コンパイルエラーが発生します。簡単にするために、古典的な瞬きの例を使用して違いを説明しましょう。または、より良いコードスニペットを使用する場合は、必ず、スニペットを回答に含め、違いを完全に説明してください。

どちらがより良い使用方法またはツールであるかについての意見はありません。

ご参考までに。開発にPlatformioを使用していて、コンパイル中にバックグラウンドで変換プロセスが発生していることに気付きました。そこで実際に何が起こっているのかを理解しようとしているので、Arduinoでコーディングすると、「純粋な」C ++バージョンも理解できます。

事前に私の質問にあなたの思慮深い回答をありがとう。


gccデスクトップ、またはAVRコンパイラ用のGCC について具体的に質問していますavr-gccか?.ino.cppファイルの間にあるよりもはるかに大きな違いがあります。
BrettAM 2016年

@BrettAM Arduino UNOとしてのGCC-AVRツールキットはターゲットボードであり、Atmel AVRチップを使用しています。質問のあいまいさを指摘してくれてありがとう。そして、はい、私ははるかに大きな違いがあることを知っています。それが私がこの質問をしている理由です。それらの違いを知るために!
RedDogAlpha 2016年

回答:


14

ここで私の答えを参照してください:クラスとオブジェクト:実際にそれらを使用するために必要なファイルタイプの数と種類は?-具体的には、IDEがどのように整理するか

少なくとも、Arduinoヘッダーファイルを含める必要があることはわかっています。

はい、そうする必要があります。

しかし、それ以上に、たとえばGCC-AVRなどを使用して.inoを.cppファイルにコンパイルすると、コンパイルエラーが発生します。

IDEは関数プロトタイプを生成します。.inoファイル内のコードは、これを必要とする場合と必要としない場合があります(通常、作成者が通常のC ++の方法でコーディングして自分で行うのに十分な規律がない限り、必要になります)。


「スケッチ」に他のファイル(他の.ino、.c、.cppファイルなど)が含まれている場合は、上記の回答で説明したように、これらをコンパイルプロセスに組み込む必要があります。

また、スケッチで使用されるライブラリを(コンパイルして)リンクする必要があります。


リンクの側面については質問していませんが、当然のことながら、コンパイル済みのさまざまなファイルをリンクして、アップロードのために.elfファイルと.hexファイルに変換する必要があります。下記参照。


メイクファイルの例

IDE出力に基づいて、しばらく前に簡単な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 

その特定の場合、.inoファイルはBlink.cpp 名前を変更して次の行を追加した、問題なくコンパイルされました。

#include <Arduino.h>

簡潔な回答をしてくれたニックに感謝します。私はあなたと同じレベルではありません。メイクファイルについてさえ考えていませんでした。だから基本的には構文は同じですが、それはオブジェクトをリンクすることに関するすべてですよね?私が分析できるようにメイクファイルを共有していただきありがとうございます。そこからさらに質問があると思います!再度、感謝します!
RedDogAlpha 2016年

上記の私のファイルは投稿したときに機能しましたが、後のIDE(ライブラリファイルの移動や名前変更のため)を微調整する必要があると思います。それでも、詳細なコンパイルを行うと、IDEが現在何を生成しているかがわかります。
Nick Gammon

10

Nick Gammonの回答にいくつかのポイントを追加したいと思います。

  • コンパイルするために.inoファイルの名前を変更する必要はありません。コンパイラにC ++(オプション-x c++)と明示的に指定すると、異常なファイル拡張子は無視され、C ++としてコンパイルされます。
  • #include <Arduino.h>.inoファイルに追加する必要はありません-include Arduino.h。コンパイラーに追加するように指示できます()。

これらのトリックを使用して、適切なコマンドラインオプションでavr-g ++を呼び出すだけで、変更なしで Blink.inoをコンパイルできます。

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

上記のコマンドラインに関するいくつかの注意:

  • /usr/local/lib/arduino/uno/libcore.aコンパイルしたArduinoコアを保存した場所です。私は同じものを何度も何度も再コンパイルするのが嫌いです。
  • -x noneコンパイラにファイル拡張子を気にするように指示するために必要です。これがないと、libcore.aがC ++ファイルであると想定されます。

これらのトリックはSudar MuthuのArduino-Makefileから学びました。これは、多くのボードやライブラリで機能する非常に一般的なMakefileです。Arduino IDEに関して欠けているのは、前方宣言だけです。


とても素敵です、エドガー!私の解決策は基本的にIDEの動作を模倣し、あなたの解決策は実際の問題をより適切に解決します。もちろんlibcore.a、事前にファイルを作成する必要があります。私の回答では、ビルドcore.aを事前に行うことができるので、各ビルドの一部である必要はないと思います。経験から、より複雑なスケッチ(たとえば、WireまたはSPIを使用)には、さらにファイルを追加する必要があることがわかっていcore.aます。
Nick Gammon

@NickGammon:そうです、MuthuのMakefile(そして、Arduino IDEだと思います)は、使用するライブラリをlibcore.aに置く傾向があります。「コアライブラリ」と思われるものがコンパイルする特定のプログラムに依存するため、このアプローチはあまり好きではありません。WireやSPIなどの単一ファイルライブラリの場合、ライブラリC ++ファイルをメインプログラムと同じコンパイルコマンドに配置することをお勧めします。そのコマンドラインは非常に長くなるので、Makefileを使用します。
Edgar Bonet 2016年

1
IDEで気に入っている点の1つは、あちこち操作する必要がないことです。とにかく単純なプロジェクトの場合、「うまくいく」だけです。
Nick Gammon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.