Ich habe neulich an einem Arduino-Projekt gearbeitet und musste meine Entwicklungsumgebung anpassen. Anstatt der Arduino IDE, nutze ich lieber den Editor Zed mit clangd als Compiler und PlatformIO für die Hardwareintegration.
Ich möchte bereits erstellten Code und Bibliotheken wiederverwenden, wenn ich neue Projekte erstelle. Obwohl der Code kompiliert und auf dem Arduino läuft, funktioniert die Zed-Integration nicht ideal, da der integrierte Linter für C/C++ dennoch Fehler/Warnungen zeigt. Das können zum Beispiel folgende Meldungen sein:
Use of undeclared identifier 'LED_BUILTIN'
Use of undeclared identifier 'Serial'
'Led.h' file not found
PlatformIO und clangd brauchen dafür dieselbe Compiler-Umgebung. Dies habe ich folgendermaßen realisiert:
1. Erstellung der PlatformIO “compilation database”
Mit PlatformIO kann man die Datei compile_commands.json generieren:
pio run -t compiledb
Dies entspricht dann in etwas folgendem Compiler-Kommando für src/main.cpp
avr-g++ ... \
-DARDUINO_AVR_UNO \
-DF_CPU=16000000L \
-DARDUINO_ARCH_AVR \
-DARDUINO=10808 \
-Iinclude \
-Isrc \
-Ilib/Led \
-I.../framework-arduino-avr/cores/arduino \
-I.../framework-arduino-avr/variants/standard \
src/main.cpp
Das ist der bevorzugte Weg anstatt die Arduino Include-Pfade in .clangd zu pflegen.
2. Arduino-Header explizit verwenden
Der Quellcode sollte die Arduino-Header explizit verwenden:
#include <Arduino.h>
3. Kein Vermischen der Pfade von Arduino IDE und PlatformIO
Zunächst hat .clangd folgende Pfade:
~/Library/Arduino15/packages/arduino/...
Diese gehören zur “Arduino IDE”-Installation. Für ein PlatformIO-Projekt befindet sich das Framework aber hier:
~/.platformio/packages/framework-arduino-avr/
Daher sollte die PlatformIO “compilation database” die Wahrheit enthalten anstatt manuell Pfade zu kopieren oder zu pflegen.
4. Diagnostik
Der folgende Befehl zeigte das wahre Problem:
clangd --check=src/main.cpp
Clangd nutzt das integrierte clang von Apple:
/Library/Developer/CommandLineTools/usr/bin/clangd
und hat das target im Compiler-Befehl von PlatformIO als macOS-ARM-Architektur erkannt:
target 'arm64-apple-darwin'
obwohl der Quellcode für etwas anderes gedacht war:
ATmega328P / AVR
Die Diagnostik liefert:
unsupported option '-mmcu=' for target 'arm64-apple-darwin'
und daraus folgt:
'avr/pgmspace.h' file not found
Das erklärt, warum die Arduino-Symbole, wie z.B. Serial, nicht aufgelöst wurden.
5. clangd muss den PlatformIO AVR Compiler nutzen
Die finale .clangd Konfiguration war:
# yaml-language-server: $schema=https://json.schemastore.org/clangd.json
CompileFlags:
CompilationDatabase: .
Compiler: /Users/<YOUR_USER>/.platformio/packages/toolchain-atmelavr/bin/avr-g++
Diagnostics:
MissingIncludes: None
UnusedIncludes: Strict
Die Compiler-Zeile in den CompileFlags sagt clangd, dass die gleiche AVR-Compiler-Toolchain verwendet werden soll, die PlatformIO nutzt. Damit nutzt clangd folgendes:
- AVR-Targets
-mmcu=atmega328p- AVR-Systemheader
- Arduino-AVR-Header
- boardspezifische Definitionen, wie z.B.
ARDUINO_AVR_UNO
Der native AVR-Compilertest bestätigt, dass die PlatformIO-Toolchain funktionierte:
/Users/<YOUR_USERNAME>/.platformio/packages/toolchain-atmelavr/bin/avr-g++ \
... \
-I.../framework-arduino-avr/cores/arduino \
-I.../framework-arduino-avr/variants/standard \
-E src/main.cpp
Und der Präprozessor fand auch HardwareSerial.h. Somit war die Arduino-Installation nicht defekt, sondern
lediglich clangd-Konfiguration.
7. Projektbibliotheken
Nachdem die AVR-Toolchain repariert war, konnte clangd die Include-Pfade des PlatformIO-Projekts aus der
compile_commands.json nutzen, z.B. -Ilib/Led, sodass
#include <Led.h> ebenfalls funktionierte.
Das zeigt, warum es sinnvoll war die Compilation-Database zu nutzen, anstatt manuell in einzelnen Projekten .clangd-Dateien zu pflegen.
Michael Hülsen