Appearance
8. Applikationen Cross-Compilieren
Manpages
Um die Hilfeseiten der Standard C Library einzusehen, installieren Sie das Ubuntu Package manpages-dev
oder falls Sie Deutsch bevorzugen manpages-de-dev
wonach per man funktionsname
die Hilfeseiten zu jeder vorhandenen C-Funktion oder System Call einsehbar ist sollten.
Beispiel: Eingabe von man gethostname
die Hilfeseite der C-Funktion gethostname()
erscheinen. Seitenweise Blättern per Leerschlag-Taste, navigieren per Cursor-Tasten, beenden mittels q
wie quit.
Sections
Die man-Pages sind in verschiedenen so genannten Sections unterteilt. Sofern es eine gleichnamige man-Page in mehreren Sections gibt ,wird die Hilfeseite der zuerst gefundenen Section angezeigt.
Beispiel: Bekanntlich existiert printf
als C Standard Library Funktion. Bei man printf
wird jedoch die Hilfeseite des printf
Console Commands anzeigt, da es selbigen tatsächlich gibt und die Hilfeseiten der Ausführbaren Programme in einer tieferen Section als jene der Library-Funktionen sind!
Man kann bei man
aber die Section auch explizit angeben, wenn man diese kennt...
Alle Bezüge in Hilfeseiten in welchen printf
ganz oder teilweise vorkommt, lassen sich per apropos printf
auffinden (resp. man -k printf
).
Dadurch kann man erfahren, dass printf
zumindest in den man-Sections 1, und 3 vorkommt.
Per man man
erfahren Sie die Zuordnung der Manpage Sections. Für uns derzeit interessant:
Section | Beschreibung |
---|---|
Section 1 und 8 | |
Section 2 | |
Section 3 |
Die gewünschte Hilfeseite der C Library Funktion printf()
erhalten Sie gem. man man
unter zusätzlicher Angabe der Section Nr, also per:
man 3 printf
man Pages sind nur auf dem Linux-Host vorhanden und nicht auf unserem Buildroot Zielsystem!
Hello World Programm
Erstellen Sie unter ~/ebssd/
ein Verzeichnis workspace und darunter ein Projektverzeichnis hello
, worin Sie ein C-Sourcefile hello.c
mit folgender Funktionalität in der Funktion main()
erstellen:
- Einlesen des Hostnamen per
gethostname()
in ein char-Array - sowie formatierte Anzeige des Rückgabewertes von
gethostname()
per Funktionprintf()
Includes
Tipp: Welche Include-Datei Sie für printf()
includen müssen, dürfte Ihnen wohl bekannt sein – andernfalls wird es man 3 printf
in einer der obersten Zeilen angezeigt! Ebenso für gethostname()
.
Compilieren und testen Sie Ihr Programm zuerst auf dem Hostsystem:
bash
gcc -o hello hello.c
./ hello
Identifizieren Sie das Dateiformat des generierten „Executable“ also des ausführbaren Programms: file hello
.
Alles wie erwartet? (Ziel Architektur, statisch oder dynamisch gelinkt, …) Ok bestens!
Wenn Sie nun versuchen wie folgt hello.c
für die ARM-Platform zu crosscompilieren, wird es vermutlich nicht klappen ( versuchen Sie's).
arm-none-linux-gnueabihf-gcc -o hello hello.c
Offensichtlich ist der betreffende Cross-Compiler obwohl von Buildroot ja heruntergeladen (oder bereits für den Custom Kernel selber heruntergeladen) nicht im "normalen" Suchpfad!
Libraries
Buildroot hat ja aus der von Buildroot heruntergeladenen Cross-Toolchain die Shared Libraries auf dem Zielsystem unter /lib
und /usr/lib
installiert. Shared Libraries sind dynamisch ladbare Libraries!
Um Bibliothekskonflikte mit diesen auf dem Zielsystem installierten Shard Libraries zu verhindern, sollte beim Corss-Compilieren von Anwendungen welche Shared Libraries verwenden (was standardmässig der Fall ist) der exakt gleiche Toolchain-Release verwendet werden!
Deshalb vermeiden wir es, über den Packet Manager oder anderweitig eine weitere Cross-Tolchain zu installieren und verwenden die von Buildroot installierte!
Um die durch Buildroot installierte Toolchain aufzufinden, suchen Sie selbige unter dem buildroot Ordner Z.b. wie folgt mittels find
Command:
bash
# je nach dem, wo der cross-compiler abgelegt wurde
find ~/ebssd/buildroot -name 'arm*gcc'
Worauf der absolute Pfad des Crosscompiler angezeigt werden sollte! (der 2. angezeigte Pfad ist korrekt!)
Um nun nicht jedes mal den gesamten Pfad angeben müssen, ergänzen Sie den Suchpfad (also die Umgebungsvariable PATH) über das (versteckte) Login-Script .profile
in Ihrem Home-Directory:
nano ~/.profile
Ergänzen Sie in dieser Datei zuunterst (nach dem fi
) eine neue Zeile mit: PATH=$PATH:<vollständiger-pfad-zum-gewünschten-bin-ordner>
Pfade
Für <vollständiger-pfad-zum-gewünschten-bin-ordner>
geben Sie den oben mit find angezeigten Ordnerpfad angeben, also ohne die Programmangabe am Schluss!
Die Datei .profile
wird von der Login-Shell nur beim erneuten Einloggen automatisch eingelesen. Für die laufende Shell können Sie diese auch mittels dem .
oder source
Shell-Command includen:
bash
. ~/.profile
Wonach Sie sich vergewissern, ob die Tools nun wirklich gefunden werden
bash
arm<TAB><TAB>
# also arm eintippen und dann 2x die Tabulatortaste betätigen
Damit sollten alle Cross-Compiler-Tools inkl. C-Compiler arm-none-linux-gnueabihf-gcc
angezeigt werden.
Command nicht gefunden
Fehlersuche: Falls arm-none-linux-gnueabihf-gcc
nicht gefunden wird, funktionierte das Setzen des Pfads offensichtlich nicht!
Ein echo $PATH
muss am Ende auch den Pfad zur Toolchain nur bis zum bin Ordner anzeigen.
Beachten Sie, den Command-Präfix 'arm-none-linux-gnueabihf-' welcher folgende Bedeutung hat:
arm | ARM v7 32-bit Architektur entsprechend der CPU-Architektur des SoCs . Diese würde übrigens auch ARM64-Bit verstehen – vorausgesetzt ein 64-Bit Linux-Kernel würde gebootet und ARM64-Bit Shared Libraries würden installiert!) |
linux | mit Linux Systemcalls sowie Virtual Memory Unterstützung (also nicht "bare metal" d.h. ohne VM) |
gnueabihf | mit GNU C/C++ Library also gnu→mit glibc, eabi → Embedded Application Binary Interface (spezifiziert Aufrufkonvention) sowie hf → mit Hardware-Floatingpoint Unterstützung. |
Welchen GCC Release hat der Compiler selbst? (Compiler aufrufen mit Option --version
)
Sofern alles klappte, melden Sie sich am Linux-System ab und neu an, damit die Toolchain in allen neuen Shells automatisch verfügbar wird (Umgebungsvariablen sind ja nicht „global“ sonder bloss „vererbt“).
Das Cross-Compilieren sollte nun erfolgreich sein:
bash
arm-none-linux-gnueabihf-gcc -o hello hello.c
Identifizieren Sie das generierte „Executable“ wiederum per:
bash
file hello
Alles wie erwartet? (Korrekte Ziel-Architektur? Statisch oder Dyamisch gelinkt?, …) Ok bestens!
Der Einfachheit halber kopieren wir das gerade erstellte hello
Programm aufs Zielsystem nach /usr/bin/
Achtung: im betreffenden Ordner sind auch von Buildroot generierte ELF-Dateien. Vermeiden Sie also Konflikte mit den dort vorhandenen Dateien resp. Dateinamen!
Kopieren Sie das gerade erstellte hello Programm über die (funktionierende!) Netzwerkverbindung zum laufenden Zielsystem mittels scp
in das Zielsystem-Verzeichnis /usr/bin/
Binary Location
Alternativ könnten Sie das hello „Binary“ auch ins Homeverzeichnis des root-Users (/root
auf dem Zielsystem) oder besser noch ins Zielsystem-Verzeichnis /usr/local/bin
kopieren, müssten dann aber die Umgebungsvariable PATH im systemweiten /etc/profile
ergänzt oder bei jedem Aufruf den gesamten Pfad angeben werden!
Hat‘s funktioniert? Andernfalls korrigieren Sie den Fehler! (Insbes. falls /usr/bin/
auf dem Target noch gar nicht existiert oder nicht im Suchpfad enthalten wäre...)
Welche Art Libraries werden gem.
file hello
(auf Hostssytem ausgeführt) verwendet?Und wie gross ist das Programm gemäss
ls -l hello
überhaupt?
Standard C Lib
Die Ausführung des Commands funktioniert also bloss, weil die GNU Standard C Library (kurz glibc
) als „Shared Libraries“ auf dem Zielsystem korrekt unter /lib
... und /usr/lib/
... installiert ist sowie beim Crosscompileieren von hello.c die exakt gleiche Library-Version referenziert wurde!
(Buildroot hat diese Shared Libraries ja aus dem "sysroot" der Cross-Toolchain in die tar-Datei kopiert...)
Übersetzen und linken Sie nochmals unter zusätzlicher Angabe der Option
-static
und verifizieren Sie danach perfile hello
ob das Programm nun wirklich statisch gelinkt wurde. (Es sollte nun!)Wie gross resp. wie viel mal grösser ist nun das Programm?
Mittels arm-none-linux-gnueabihf-strip hello
könnten Sie noch alle (Debug-) Symbol-Information aus dem Programm entfernen, das „Binary“ bleibt aber trotzdem noch recht gross für einen „Einzeiler“!
Statisches Linken
Selbst ein kleines „Hello World“-Programm ist also mit statisch eingebundener GNU Standard C Library recht gross!
Das „vollgepackte“ dynamisch gelinkte Programm /bin/busybox
ist sogar noch kleiner!
Für einzelne Programme wäre dies kein Problem,aber bei einer grossen Anzahl Programme ist es doch sinnvoller die Libraries dynamisch einzubinden (d.h. als so genannte „Shared Libraries“).
Statisches linken verlangsamt auch die Programmstartzeit und verschwendet insbes. bei einer grösseren Anzahl Programmen viel Flash-Speicher (SD-Karte) und Hauptspeicher (DRAM), wogegen Shared Libraries wie der Name sagt, unter den laufenden Programmen „geshared“ also gemeinsam genutzt werden!
Mit Buildroot wäre es auch möglich, eine Toolchain mit der ucLibc Library generieren zu lassen, was sich jedoch nur bei sehr knappem Systemspeicher lohnt (also bei sehr wenig Flash und/oder DRAM)! (vgl. http://www.uclibc.org/FAQ.html#why_should_i)
Da wir auf unserem Zielsystem reichlich Speicherplatz haben (sowohl auf der SD wie im RAM), bleiben wir bei der durch Buildroot installierten GNU Toolchain beinhaltend die GNU Standard C Library (glibc)
Shared Libraries
Diese Toolchain enthält also die GNU C Standard Library und zwar gleich doppelt, einerseits statisch linkbar (*.a
) als auch als Shared-Libraries (*.so
steht für „Shared Object“). Beide Library-Varianten befinden sich unter dem so genannten sysroot
Verzeichnis der Toolschain.
Das sysroot
des Hostsystems ist zuoberst im Root-Verzeichnis auf /
, wogegen sich das sysroot der Crosstoolchain wie folgt anzeigen lässt: arm-none-linux-gnueabihf-gcc --print-sysroot
Wenn Sie nun unter dem Toolchain-sysroot die Grösse der Zielsystem-Verzeichnisse /lib
und /usr/lib
bestimmen (z.B. auf dem Zielsystem mittels du -sh /lib /usr/lib
) und mit jenen auf dem Hostsystem vergleichen – also nach cd
ins betreffende sysroot-Verzeichnis mit du -sh lib usr/lib
, erkennen Sie, dass Buildroot offensichtlich bloss ein Bruchteil aller vorhandenen Shared Libraries kopiert hat!
fehlende libs
Beim manuellen kompilieren und zufügen von Anwendungen zu einer Buildroot Installation kann es somit passieren, dass die eine oder andere Shared-Libraries fehlt oder fehlen, d.h. nicht auf dem Zielsystem installiert sind.
Gegebenenfalls müssten Sie die betreffenden Shared-Libraries manuell aus dem sysroot der Toolchain auf das Zielsystem resp. deren SD kopieren kopieren (per cp ...
resp. scp ...
).
Aber wie erkennt man, welche „Shared Libraries“ von einem Programm benötigt werden?
Hierzu gibt es auf dem Hostsystem der ldd-Befehl, welcher die von einem Programm benötigten Shared-Libraries auflistet, beispielsweise betreffend der bash Shell mit: ldd /bin/bash
.
ldd
auf dem Host funktioniert jedoch nicht für crosscompilierte Programme und nicht immer ist ldd
auf einem Embedded Zielsystem vorhanden.
In diesem Fall kann statt dessen der so genannte „Library Loader“ (also jene „Shared Library“, welche alle anderen Shared Libraries nachzuladen vermag) selbst als Programm mit Option --list
aufgerufen werden, auf dem Zielsystem also mit:
bash
/lib/ld-linux-armhf.so.3 --list /usr/bin/hello
- Welche Shared Libraries werden aufgelistet und wozu werden diese in
hello
wohl verwendet?
Wenn Sie obige Command mehrfach aufrufen erkennen Sie, dass die Loader-Adressen der Shared Libraries jedesmal ändert. Aus Sicherheitsgründen resp. um Hacker-Angriffe zu erschweren führt Linux beim Laden der Programme eine Address Space Layout Randomization (ASLR) durch, vgl. https://de.wikipedia.org/wiki/Address_Space_Layout_Randomization.
Libraries und Memory Map
Damit einerseits der GNU Library Loader die von einer Applikation gewünschten Libraries schneller auffinden kann, andererseits dieser auch Libraries ausserhalb der Standard-Verzeichnisse /lib
und /usr/lib
finden kann, ist zumindest auf dem Hostsystem ein Library-Index Cache-Datei /etc/ld.so.cache
vorhanden.
Falls Buildroot Programme installiert hätte, welche abgesehen von der Standard C Library weitere Shared Libraries benötigen, hätte Buildroot diese Index-Datei für uns ebenfalls erstellt.
Zudem liessen sich weitere Library-Verzeichnisse in /etc/ld.so.conf
eintragen, wonach mittels ldconfig
der Library-Cache neu erstellt werden müsste. Leider hat Buildroot diesen Command nicht aus dem Toolchain sysroot auf die Zielsystem-Partition kopiert, da es gegen die Philosophie von Buildroot spricht, nachträglich das Image zu ändern. (Man könnte buildroot aber entsprechend konfigurieren oder ldconfig manuell aus dem "sysroot" auf Zielsystem kopieren).
Die „Memory Map“ laufender Programme (inkl. eingebundene Shared Libraries) lässt sich hingegen über das Pseudofilesystem /proc
per cat /proc/<pid>/maps
ermitteln (an Stelle von <pid>
die Prozess-Id des gewünschten Prozesses angeben).
Betrachten Sie auf dem Host- wie auf dem Zielsystem auch noch die Memory Map des init-Prozesses.
Der init Prozess hat bekanntlich immer die PID=
, da dieser ja als erster Prozess gestartet wurde.
Verifizieren Sie dies per ps
resp. ps -ef
.
Makefile für Hello-Programm
Um den Aufruf des Buildvorganges zu vereinfachen, sodass der Build-Vorgang mittels einem einfachen make
erfolgen kann, erstellen Sie im Projektordner hello
folgende Datei namens Makefile
.
Makefile
CC = arm-none-linux-gnueabihf-gcc
CFLAGS = -mthumb -march=armv7-a
CFLAGS += -Wall
all: hello
hello: hello.c
$(CC) $(CFLAGS) -o hello hello.c #unbedingt ein TAB am Anfang dieser Zeile verwenden!!!
Whitespace
Achtung: der Whitespace vor $(CC) …
muss zwingend ein <Tab>
Zeichen sein, keine Leerschläge!
Bemerkung zu den angegebenen CFLAGS:
- Mit Angabe der Compiler-Optionen -mthumb und -march=armv7-a wird statt dem defaultmässigen 32-Bit ARM Maschinencode der kompaktere (gemischt 16/32-Bit) „Thumb2“ Maschinencode generiert.
- ... unsere Ziel-CPU (auf dem SoC) versteht jedoch beides, d.h. diese CFLAGs könnten ohne weiteres auch weggelassen werden.
CFLAGS
Sofern das Ausgabefile hello
schon existiert und dieses neuer als der abhängige Sourcecode hello.c
ist, wird make bekanntlich die Commands in der Regel hello: hello.c
nicht anwenden und deshalb hello.c
nicht neu übersetzt!
Somit erfolgt z.B. nach Änderungen am Makefile (z.B. ändern der CFLAGS-Optionen) keine Neukompilation beim Ausführen von make
(s.a. nächstes Kapitel).
Übrigens: die make-Rule hello: hello.c
müssten wir eigentlich gar nicht aufführen, denn sie wird durch eine „Built-In Rule“ von make bereits abgedeckt. Um jedoch vom make-Release unabhängig zu sein und der besseren Dokumentation wegen, sollten derartige make built-In-Rules besser gar nicht verwendet werden!
Makefile vervollständigen
Testen Sie das Makefile per make
aus dem hello-Projektverzeichnis, wobei Sie vorgängig das hello-Executable löschen (nicht den Sourcecode!).
Um ein Neuerstellen von 'hello' zu erzwingen, könnten Sie selbiges jeweils manuell löschen und danach erneut make
ausführen. Üblicherweise erstellt man hierzu eigens eine Makefile-Rule namens clean
, mit welcher per Aufruf von make clean
das Executable (hello) sowie etwelche weitere Objektfiles gelöscht werden.
Achtung
Die erste Rule im Makefile ist die Default-Rule, weshalb bei uns die Rule 'all' zuoberst sein muss resp. bleiben soll!
- Erstellen Sie auch eine Rule
clean:
mit welcher Sie das hello-Executable löschen per:rm -f hello
Da clean
keine effektiv zu erstellende Ziel-Datei ist, sondern bloss ein „scheinbares“ (phony
) Ziel, ergänzen Sie zuunterst im Makefile noch die Zeile:
.PHONY: clean
(Die Rule 'all' ist übrigens defaultmässig eine "phony rule")
Erstellen Sie zudem noch eine Rule install:
, mit welcher das hello-Programm mittels scp
auf's Zielsystem unter /usr/bin/
kopiert wird.
SSH Keys
Spätestens wenn ein System an einem LAN oder gar per Port-Forwarding am Internet angeschlossen wird, sollte ein sicheres Passwort auf dem Ziel- resp. Remotesystem verwendet werden.
Statt dieses bei jedem Remote-Login per ssh oder scp manuell anzugeben, verwendet man besser und bequemer eine asymetrische „SSH Key-Based Authentication“. Hierzu ist einmalig auf dem Hostsystem ein RSA-Schlüsselpaar per ssh-keygen -t rsa -b 2048
zu generieren, danach kann der generierte Public Key per ssh-copy-id root@192.168.x.y
auf das Zielsystem kopiert werden. Der lokale Private Key unter dem ~/.ssh/
wird hingegen „geheim“ gehalten!
Sofern das Zielsystem später mal gewechselt oder neu aufgesetzt wird, reklamiert ssh/scp aus Sicherheitsgründen. Um das Problem zu korrigieren muss der "Fingerprint" des Remote Hosts aus der lokalen ~/.ssh/known_hosts
Liste entfernt werden – bequem mittels ssh-keygen -R 192.168.x.y
.
Generieren Sie wie oben beschreiben ein RSA-Schlüsselpaar und kopieren Sie den Public Key wie angegeben aufs Zielsystem.
Nun sollte ein
make clean && make && make install
oder kürzer einmake clean all install
klappen!
Wenn alles klappt, suchen/ersetzen Sie im Makefile noch alle Vorkommnisse von hello
mit $(APP)
und definieren zuoberst eine make-Variable APP=hello
, womit das Makefile für zukünftige Anwendungen einfach anpassbar wird!
Remote-Debugging mit GDB auf Console-Ebene
Ein rudimentäres GDB Cross-Debuggen ist aber auch mittels gdb möglich, und via gdb-Option -tui
sogar mit einem „Trivial User Interface“ .
- Der tui Mode von GDB erfordert jedoch die Packages: libncursesw5 libpython2.7:
sudo apt install libncursesw5 libpython2.7
- Ergänzen Sie im Makefile in einer der CFLAGS Zeilen noch
-g
, damit der Compiler dem Executable die Debug-Informationen zufügt:CFLAGS += -Wall -g
- Starten Sie nach Neuerstellung von hello selbiges wie folgt auf dem Zielsystem unter der Kontrolle des GNU Debug Servers 'gdbserver':
bash
gdbserver :2000 /usr/bin/hello
Das Programm gdbserver lädt das angegebene Programm (/usr/bin/hello
) in den Speicher und empfängt auf dem angegebenen und hoffentlich freien TCP-Port (2000) auf allen lokalen IP-Interfaces auf eine eingehende Verbindung und in der Folge auf Steuercommands des entfernten gdb-Debugger-Frontends. (Sofern Sie in der Buildroot menuconfig Unter Toolchain den dbserver ausgewühlt haben, wurde dieses aus dem „sysroot“ der Toolchain auf das Zielsystem Image unter /usr/bin/
kopiert!)
Starten Sie aus dem hello-Projektverzeichnis auf dem Hostssytem nun den GDB Cross-Debugger der Toolchain mit dem „Terminal User Interface“ (-tui) per:
arm-none-linux-gnueabihf-gdb -tui hello
Wonach Sie in der GDB-Console folgendes eingeben, um die Remote-Verbindung zum gdbserver
herzustellen und ein paar Schritte zu Debuggen:
(gdb) target remote 192.168.254.254:2000 # stellt Remote-Verbindung zum gdbserver her
(gdb) br main # setzt Breakpoint auf Symbol 'main'
(gdb) cont # führt Programm bis zum Breakpoint ('main') aus
(gdb) next # führt bis zur nächsten Sourcezeile aus (inkl. Unterprogramme)
(gdb) step # steppt auch in Unterprogramme (ohne setzen des sysroot ev. crash)
(gdb) finish # step out (Ausführen der aktive Funktion bis und mit Rücksprung)
(gdb) print <variablenname> # um eine Variable zu inspizieren
(gdb) quit # aus gdb aussteigen
GDB Quick References und Anleitungen finden Sie auf:
- http://users.ece.utexas.edu/~adnan/gdb-refcard.pdf
- https://www-users.cs.umn.edu/~kauffman/2021/gdb.html
- http://cs107e.github.io/guides/gdb/
Je nach gcc-
resp. gdb-
Version erfolgt eventuell ein Crash beim Steppen in C Standard Library Funktionen, sofern das GDB-Frontend (arm-none-linux-gnueabihf-gdb
) die falschen Shared-Libraries annimmt (nämlich jene des Hostsystems mit x86-Maschinencode). Gegebenenfalls lässt sich dieses Problem lösen, indem entweder die Anwendung hello statisch gelinkt wird (was bekanntlich per Compilerflag -static
möglich ist) oder indem dem GDB-Frontend in der GDB-Console der Pfad zum richtigen sysroot bekanntgegeben wird per:
(gdb) set sysroot <sysroot-path>
Den <sysroot-path>
(also den Pfad zu den Shared Libraries der Cross-Toolchain) erfahren Sie per:
arm-none-linux-gnueabihf-gcc --print-sysroot
Ein vorzeitiges Abbrechen von hello
mittels Ctrl-C
auf dem Zielsystem ist bei angehaltenem Debugger übrigens nicht möglich, da der Prozess hello
ja unter der Kontrolle des gdbserver
Prozesses angehalten ist und gdbserver
selbst wiederum den Standard-Input dem (angehaltenen) Prozess hello
überlässt.
Um beide Prozesse zu beenden müssen Sie sich schon auf dem Zielsystem unter einer weiteren Shell-Console (z.B. via ssh
) einloggen und danach z.B. mittels killall gdbserver hello
beide Prozesse beenden (oder „brute force“ das Zielsystem rebooten...)
Damit Sie das set sysroot …
nicht bei jeder Debugsession manuell neu eingeben müssen, definieren Sie den obigen gdb-Command am Besten im Projektverzeichnis in die (versteckte) und von gdb
automatisch eingelesene Datei .gdbinit
was Sie wie folgt realisieren können:
bash
echo "set sysroot `arm-none-linux-gnueabihf-gcc --print-sysroot`" > .gdbinit
Neuere GDB-Releases lassen aus Sicherheitsgründen keine .gdbinit
-Dateien aus beliebigen Ordnern zu. Dies kann aber in einer .gdbinit
-Datei im Homeverzeichnis mittels eines Eintrages set auto-load safe-path /
zugelassen werden. Führen Sie deshalb auch noch folgendes aus:
bash
echo 'set auto-load safe-path /' > ~/.gdbinit
Der Bequemlichkeit halber können Sie in der Projekt .gdbinit Datei auch folgende Zeilen ergänzen:
target remote 192.168.254.254:2000 # stellt Remote-Verbindung zum gdbserver her
br main # setzt Breakpoint auf Symbol 'main'
cont # führt das Programm bis zum Beakpoint ('main') aus
Wenn bisher alles geklappt hat und Sie (fakultativ) noch eine weitere Herausforderung suchen, können Sie im Makefile zusätzlich eine Phony-Rule namens gdb
ergänzen, in welcher dann zuerst der gdbserver
auf dem Zielsystem gestartet und danach der Cross gdb auf dem Host gestartet wird.
Für komplexere Applikationen lohnt sich die Evaluierung einer Featurereichen IDE wie z.B. Eclipse, VS-Code, Geany oder CLion. Häufig lohnt es sich aber, sich nicht vollständig von der IDE abhängig zu machen und auch weiter das Arbeiten mit einem Editor und make
zu unterstützen.