Liệu .ino Arduino Sketch sẽ biên dịch trực tiếp trên GCC-AVR?


10

Được rồi, tất cả chúng ta đã thấy những câu hỏi đó trên web như Arduino vs C ++ hoặc các câu hỏi tương tự khác. Và phần lớn các câu trả lời thậm chí không chạm đến sự khác biệt biên dịch ngoài thông qua thông tin trừu tượng.

Câu hỏi của tôi nhằm giải quyết sự khác biệt thực tế (không phải tùy chọn) trong cách tệp .ino được đổi tên thành tệp .cpp hoặc phần mở rộng tệp tương tự khác cho c ++ sẽ biên dịch bằng GCC-AVR. Tôi biết rằng ở mức tối thiểu bạn phải bao gồm tệp tiêu đề Arduino, nhưng ngoài ra, điều gì sẽ gây ra lỗi biên dịch nếu biên dịch tệp .ino thành .cpp bằng cách sử dụng, ví dụ như GCC-AVR. Để đơn giản, hãy sử dụng ví dụ chớp mắt cổ điển để giải thích sự khác biệt là gì. Hoặc nếu bạn có một đoạn mã tốt hơn để sử dụng, xin vui lòng, bằng mọi cách, hãy bao gồm đoạn mã trong câu trả lời của bạn và giải thích cặn kẽ sự khác biệt.

Xin vui lòng không có ý kiến ​​nào là cách tốt hơn để sử dụng.

FYI. Tôi sử dụng Platformio để phát triển và tôi nhận thấy một quá trình chuyển đổi xảy ra đằng sau hậu trường trong quá trình biên dịch. Tôi đang cố gắng để hiểu những gì đang thực sự xảy ra ở đó, vì vậy khi tôi viết mã trong Arduino, tôi cũng hiểu phiên bản C ++ "thuần túy".

Cảm ơn câu trả lời chu đáo của bạn cho câu hỏi của tôi trước.


Bạn đang hỏi cụ thể về gccmáy tính để bàn của bạn, hoặc trình biên dịch GCC cho AVR avr-gcc? có một sự khác biệt lớn hơn nhiều so với giữa a .inovà một .cpptập tin.
BrettAM

@BrettAM Bộ công cụ GCC-AVR với tư cách là Arduino UNO là bảng mục tiêu và sử dụng chip Atmel AVR, như tôi chắc chắn bạn biết. Cảm ơn vì đã gọi ra sự mơ hồ trong câu hỏi của tôi. Và vâng tôi biết rằng có một sự khác biệt lớn hơn nhiều. Đó là lý do tại sao tôi hỏi câu hỏi này. Để tìm hiểu những khác biệt đó là gì!
RedDogAlpha

Câu trả lời:


14

Xem câu trả lời của tôi ở đây: Các lớp và đối tượng: tôi thực sự cần bao nhiêu và loại tệp nào để sử dụng chúng? - cụ thể: Cách IDE tổ chức mọi thứ .

Tôi biết rằng ở mức tối thiểu bạn phải bao gồm tệp tiêu đề Arduino

Có bạn sẽ cần phải làm điều đó.

nhưng ngoài ra, điều gì sẽ gây ra lỗi biên dịch nếu biên dịch tệp .ino thành .cpp bằng cách sử dụng, ví dụ như GCC-AVR.

IDE tạo các nguyên mẫu hàm cho bạn. Mã trong tệp .ino có thể hoặc không cần điều này (có thể sẽ trừ khi tác giả đủ kỷ luật để viết mã theo cách C ++ thông thường và tự thực hiện chúng).


Nếu "bản phác thảo" chứa các tệp khác (ví dụ: các tệp .ino, .c hoặc .cpp khác) thì chúng cần được kết hợp trong quá trình biên dịch như tôi mô tả trong câu trả lời của tôi được đề cập ở trên.

Ngoài ra, bạn sẽ cần (biên dịch và) liên kết trong bất kỳ thư viện nào được sử dụng bởi bản phác thảo.


Bạn chưa hỏi về khía cạnh liên kết của mọi thứ, nhưng tự nhiên các tệp khác nhau, như được biên dịch, cần phải được liên kết với nhau, sau đó chuyển thành tệp .elf và .hex cho mục đích tải lên. Xem bên dưới.


Ví dụ makefile

Dựa trên đầu ra IDE, tôi đã tạo một tệp đơn giản một lúc trước :

#
# 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 

Trong trường hợp cụ thể đó, tệp .ino được biên dịch mà không gặp sự cố nào sau khi đổi tên thành Blink.cpp và thêm dòng này:

#include <Arduino.h>

Cảm ơn Nick vì câu trả lời ngắn gọn của bạn, tôi không ở gần mức bạn và thậm chí không nghĩ về một tập tin thực hiện. Vì vậy, về cơ bản cú pháp là như nhau, nó chỉ là tất cả về liên kết các đối tượng, phải không? Cảm ơn bạn đã chia sẻ tập tin make của bạn để tôi mổ xẻ. Tôi chắc chắn sẽ có nhiều câu hỏi phát sinh từ đó! Cảm ơn một lần nữa!
RedDogAlpha

Tệp của tôi ở trên đã hoạt động khi tôi đăng nó, nhưng tôi tin rằng có thể cần điều chỉnh cho các IDE sau này (vì chúng di chuyển xung quanh hoặc đổi tên các tệp thư viện). Tuy nhiên, thực hiện một trình biên dịch dài dòng cho thấy IDE hiện đang tạo ra cái gì sẽ giúp bạn bắt đầu.
Nick Gammon

10

Tôi chỉ muốn thêm một vài điểm vào câu trả lời của Nick Gammon:

  • Bạn không cần đổi tên tệp .ino để biên dịch nó: nếu bạn nói rõ ràng với trình biên dịch đó là C ++ (tùy chọn -x c++), nó sẽ bỏ qua phần mở rộng tệp bất thường và biên dịch nó thành C ++.
  • Bạn không cần thêm #include <Arduino.h>vào tệp .ino: bạn có thể yêu cầu trình biên dịch làm điều đó cho bạn ( -include Arduino.h).

Sử dụng các thủ thuật đó, tôi có thể biên dịch Blink.ino mà không cần sửa đổi , chỉ bằng cách gọi avr-g ++ với các tùy chọn dòng lệnh thích hợp:

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

Một vài lưu ý về dòng lệnh trên:

  • /usr/local/lib/arduino/uno/libcore.alà nơi tôi lưu lõi Arduino đã biên dịch. Tôi ghét biên dịch lại nhiều lần cùng một thứ.
  • -x nonelà cần thiết để báo cho trình biên dịch nhớ lại các phần mở rộng tập tin. Nếu không có nó, nó sẽ giả sử libcore.a là một tệp C ++.

Tôi đã học được những mánh khóe đó từ Arduino-Makefile của Sudar Muthu . Đây là một Makefile rất chung hoạt động với nhiều bảng và với các thư viện. Điều duy nhất còn thiếu liên quan đến Arduino IDE là các khai báo về phía trước.


Rất đẹp, Edgar! Giải pháp của tôi về cơ bản bắt chước những gì IDE làm, của bạn giải quyết vấn đề thực tế để xử lý theo cách gọn gàng hơn nhiều. Tất nhiên bạn sẽ phải làm cho các libcore.atập tin trước. Tôi cho rằng các dòng trong câu trả lời của tôi core.acó thể được thực hiện trước, vì vậy chúng không phải là một phần của mỗi bản dựng. Kinh nghiệm đã chỉ ra rằng các bản phác thảo phức tạp hơn (ví dụ: sử dụng Dây hoặc SPI) cần thêm các tệp để thêm vào core.a.
Nick Gammon

@NickGammon: Đúng vậy, Makefile của Muthu (và, tôi giả sử, Arduino IDE) có xu hướng đặt bất kỳ thư viện nào bạn sử dụng trong libcore.a. Tôi không thực sự thích cách tiếp cận này, vì nó làm cho thư viện lõi được cho là của LĐNH phụ thuộc vào chương trình cụ thể mà bạn biên dịch. Đối với các thư viện tệp đơn, như Dây hoặc SPI, tôi thích chỉ đặt tệp C ++ của thư viện trong cùng một lệnh biên dịch như chương trình chính. Dòng lệnh đó khá dễ dàng, vì vậy tôi sử dụng Makefile.
Edgar Bonet

1
Một trong những điều tôi thích về IDE là bạn không cần phải loay hoay. Đối với các dự án đơn giản, nó "chỉ hoạt động".
Nick Gammon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.