Guten Tag, Habr!
Heute möchte ich meine Entwicklungserfahrung fĂŒr Mini-Computer unter Linux (RPI, BBB und andere) in der Programmiersprache D teilen. Unter dem Schnitt finden Sie vollstĂ€ndige Anweisungen, wie Sie dies ohne Schmerzen tun können. Na ja, oder fast ... =)

Warum d?
Bei der Arbeit bestand die Aufgabe darin, ein Ăberwachungssystem fĂŒr ARM zu schreiben, selbst als groĂer Fan von D, und ich bezweifelte, dass es als Hauptwerkzeug verwendet werden sollte. Im Allgemeinen bin ich keine skurrile Person, und ich bin schon lange auf D, also dachte ich, es wĂ€re einen Versuch wert und ... nicht alles ist so einfach. Einerseits gab es keine besonderen Probleme (mit Ausnahme eines nicht ganz klaren, das mit der EinfĂŒhrung der neuen Version des Compilers einherging), andererseits können Leute, die fĂŒr ARM entwickeln, stĂ€ndig denken, dass das Toolkit ĂŒberhaupt nicht bereit ist. Es liegt an Ihnen.
Toolkit
Ich kann Visual Studio Code
mit dem D Programming Language
Plugin von comrade empfehlen. WebFreak (Jan Jurzitza). In den Einstellungen können Sie die Beta Stream
Einstellung so einstellen, dass immer die neueste Version von serve-d
verfĂŒgbar ist. Das Plugin selbst installiert die erforderliche Software.
Allgemeine Struktur des Projekts
Im Allgemeinen stellte sich heraus, dass es ziemlich verwirrt war (im Vergleich zu dem ĂŒblichen Projekt auf D), aber wie es mir scheint, ist es ziemlich flexibel und bequem.
. âââ arm-lib/ | âââ libcrypto.a | âââ libssl.a | âââ libz.a âââ docker-ctx/ | âââ Dockerfile | âââ entry.sh âââ source | âââ app.d âââ .gitignore âââ build-docker âââ ddb âââ dub.sdl âââ ldc âââ makefile
arm-lib
- Bibliotheken, die fĂŒr die Funktion unserer Anwendung erforderlich sind (kompiliert unter arm)
docker-ctx
- Kontext zum Zusammenstellen eines Docker-Images
entry.sh
- fĂŒhrt einige Aktionen fĂŒr jeden spĂ€teren Start des Containers aus, ĂŒber die spĂ€ter
dub.sdl
- Projektdatei in D, mit der Sie Bibliotheken von Drittanbietern und vieles mehr dub.sdl
können
build-docker
- Container-Build-Skript (im Wesentlichen 1 Zeile, aber immer noch)
ddb
- ddb
D builder - Container- ddb
(auch eine Zeile, aber eigentlich bequemer)
ldc
- ein Skript, mit dem Sie ldc mit allen erforderlichen Parametern aufrufen können
makefile
- enthĂ€lt Build-Rezepte fĂŒr Arm und x86 sowie zusĂ€tzliche Aktionen
source/app.d
- source/app.d
Ein paar Worte zu arm-lib
.
Es gibt die Dateien, die erforderlich sind, damit Vibe funktioniert. Das HinzufĂŒgen von BinĂ€rdateien zum Repository ist eine schlechte Form. Um Ihr Leben zu vereinfachen, ist es hier jedoch einfacher, genau das zu tun. Sie können sie in den Container dockert-ctx
. Um das Rezept fĂŒr die Containerassemblierung vollstĂ€ndig zu dockert-ctx
, mĂŒssen Sie den Ordner arm-lib
in dockert-ctx
speichern. Der Geschmack und die Farbe ...
Allgemeiner Montagealgorithmus
./ddb make
ddb
startet den Container und fĂŒhrt das Skript entry.sh
entry.sh
konfiguriert dub
wenig so, dass es den Bibliotheksordner im Container verwendet, der sich im aktuellen Verzeichnis befindet, sodass Sie die im Projekt verwendeten Bibliotheken beim Neustart der Assembly nicht herauspumpen und sammeln könnenentry.sh
am Ende die Kontrolle an den Eingabebefehl (in unserem Fall make
)make
liest wiederum makefile
- Alle Flags fĂŒr Cross-Compilation und Build-Verzeichnis werden im
makefile
gespeichert, eine dub
Call-Line wird gebildet - Beim Aufruf von
dub
ldc
Skript aus dem aktuellen Verzeichnis als Compiler ĂŒbergeben und Umgebungsvariablen festgelegt - Laufzeitbibliotheken werden im
makefile
als Make-up-AbhÀngigkeiten festgelegt, die, falls sie fehlen, vom Programm ldc-build-runtime
erfasst werden - Variablen werden an das
ldc
Skript und an die dub.sdl
Parameter ĂŒbergeben
Der Inhalt der Hauptdateien
Dockerfile
Da wir unter RPI3 schreiben werden, wÀhlen wir das Image des Basis- debian:stretch-slim
Systems aus debian:stretch-slim
, wobei gcc-arm-linux-gnueabihf
dieselbe Version von glibc
wie die offizielle Raspbian-Distribution verwendet (es gab ein Problem mit fedora, bei dem der Cross-Compiler-Betreuer eine zu frische Version von glibc
)
FROM debian:stretch-slim RUN apt-get update && apt-get install -y \ make cmake bash p7zip-full tar wget gpg xz-utils \ gcc-arm-linux-gnueabihf ca-certificates \ && apt-get autoremove -y && apt-get clean ARG ldcver=1.11.0 RUN wget -O /root/ldc.tar.xz https://github.com/ldc-developers/ldc/releases/download/v$ldcver/ldc2-$ldcver-linux-x86_64.tar.xz \ && tar xf /root/ldc.tar.xz -C /root/ && rm /root/ldc.tar.xz ENV PATH "/root/ldc2-$ldcver-linux-x86_64/bin:$PATH" ADD entry.sh /entry.sh RUN chmod +x /entry.sh WORKDIR /workdir ENTRYPOINT [ "/entry.sh" ]
Der ldc
Compiler wird von github
ldc
und dort basierend auf dem aktuellen llvm
.
entry.sh
#!/bin/bash if [ ! -d ".dpack" ]; then mkdir .dpack fi ln -s $(pwd)/.dpack /root/.dub exec $@
Hier ist alles einfach: Wenn es keinen .dpack
Ordner gibt, erstellen Sie mit .dpack
einen symbolischen Link zu /root/.dub
.
Auf diese Weise können Sie die vom dub
heruntergeladenen Pakete im Projektordner speichern.
Build-Docker, ddb, ldc
Dies sind drei einfache einzeilige Dateien. Zwei davon sind optional, aber praktisch, aber fĂŒr Linux (Bash) geschrieben. FĂŒr Windows mĂŒssen Sie Ă€hnliche Dateien im lokalen Skript erstellen oder einfach von Hand ausfĂŒhren.
build-docker
startet den Container-Build (einmal aufgerufen, nur fĂŒr Linux):
#!/bin/bash docker build -t dcross docker-ctx
ddb
startet den Container fĂŒr die Assembly und ĂŒbergibt Parameter (nur Linux):
#!/bin/bash docker run -v `pwd`:/workdir -t --rm dcross $@
Bitte beachten Sie, dass der Containername dcross
verwendet dcross
(der Name selbst spielt keine Rolle, muss aber in beiden Dateien ĂŒbereinstimmen) und der Befehl pwd
verwendet wird, Dockerfile
aktuelle Verzeichnis in /workdir
(das Verzeichnis wird in der Dockerfile
WORKDIR
als WORKDIR
Dockerfile
) (in win mĂŒssen Sie anscheinend %CD%
).
ldc
startet ldc
seltsamerweise unter Verwendung von Umgebungsvariablen (nur Linux, aber es startet im Container, sodass es nicht geÀndert werden muss, um unter Win zu erstellen):
#!/bin/bash $LDC $LDC_FLAGS $@
dub.sdl
Zum Beispiel wird es ganz einfach sein:
name "chw" description "Cross Hello World" license "MIT" targetType "executable" targetPath "$TP" dependency "vibe-d" version="~>0.8.4" dependency "vibe-d:tls" version="~>0.8.4" subConfiguration "vibe-d:tls" "openssl-1.1"
targetPath
wird aus der Umgebungsvariablen ĂŒbernommen, da dub
keine Felder des Assembly-Rezepts nach Plattform angeben kann (z. B. lflags "-L.libs" platform="arm"
fĂŒgt dem Linker nur dann ein Flag hinzu, wenn unter arm erstellt wird).
Makefile
Und hier ist das interessanteste. TatsÀchlich wird make
nicht zum Erstellen als solches verwendet, es wird ein dub
dafĂŒr aufgerufen, und der dub
selbst ĂŒberwacht, was wieder zusammengesetzt werden muss und was nicht. Mit Hilfe von makefile
alle erforderlichen Umgebungsvariablen gebildet und in komplexeren FĂ€llen zusĂ€tzliche Befehle ausgefĂŒhrt (Erstellen von Bibliotheken in C, Packen von Aktualisierungsdateien usw.).
Der Inhalt des makefile
gröĂer als der Rest:
# arm arch = arm # target path -- , TP = build-$(arch) LDC_DFLAGS = -mtriple=armv7l-linux-gnueabihf -disable-inlining -mcpu=cortex-a8 # EMPTY := SPACE :=$(EMPTY) $(EMPTY) LDC_BRT_DFLAGS = $(subst $(SPACE),;,$(LDC_DFLAGS)) ifeq ($(force), y) # # , .. dub FORCE = --force else FORCE = endif ifeq ($(release), y) BUILD_TYPE = --build=release else BUILD_TYPE = endif DUB_FLAGS = build --parallel --compiler=./ldc $(FORCE) $(BUILD_TYPE) $(info DUB_FLAGS: $(DUB_FLAGS)) # LDC = ldc2 LDC_BRT = ldc-build-runtime # ldc, runtime ARM LDC_RT_DIR = .ldc-rt # gcc GCC = arm-linux-gnueabihf-gcc ifeq ($(arch), x86) LDC_FLAGS = else ifeq ($(arch), arm) LDC_FLAGS = $(LDC_DFLAGS) -LL./$(LDC_RT_DIR)/lib -LL./arm-lib -gcc=$(GCC) else $(error unknown arch) endif DUB = TP=$(TP) LDC=$(LDC) LDC_FLAGS="$(LDC_FLAGS)" dub $(DUB_FLAGS) # .PHONY: all clean rtlibs stat # all: rtlibs $(DUB) DRT_LIBS=$(addprefix $(LDC_RT_DIR)/lib/, libdruntime-ldc.a libdruntime-ldc-debug.a libphobos2-ldc.a libphobos2-ldc-debug.a) $(DRT_LIBS): CC=$(GCC) $(LDC_BRT) -j8 --dFlags="$(LDC_BRT_DFLAGS)" --buildDir=$(LDC_RT_DIR) \ --targetSystem="Linux;UNIX" BUILD_SHARED_LIBS=OFF # D runtime ARM rtlibs: $(DRT_LIBS) # stat: find source -name '*.d' | xargs wc -l clean: rm -rf $(TP) rm -rf .dub $(LDC_BRT) --buildDir=$(LDC_RT_DIR) --resetOnly
Mit einem solchen makefile
können Sie ein Projekt unter Arm und x86 mit fast einem Befehl erstellen:
./ddb make ./ddb make arch=x86 # x86 make arch=x86 # host ldc
Dateien fĂŒr arm werden in build-arm
, fĂŒr x86 in build-x86
.
app.d
Nun, fĂŒr die Vorspeise, fĂŒr das ganze Bild, app.d
der app.d
Code:
import vibe.core.core : runApplication; import vibe.http.server; void handleRequest(scope HTTPServerRequest req, scope HTTPServerResponse res) { if (req.path == "/") res.writeBody("Hello, World!", "text/plain"); } void main() { auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["::1", "0.0.0.0"]; auto l = listenHTTP(settings, &handleRequest); scope (exit) l.stopListening(); runApplication(); }
Jeder braucht jetzt web =)
Fazit
Im Allgemeinen ist nicht alles so kompliziert, wie es auf den ersten Blick scheint. Es ist nur so, dass ein universeller Ansatz noch nicht fertig ist. Persönlich habe ich viel Zeit damit verbracht, auf make
. Bei ihm ging alles irgendwie einfacher und abwechslungsreicher.
Sie mĂŒssen jedoch verstehen, dass D nicht Go ist. In D ist es ĂŒblich, externe Bibliotheken zu verwenden, und Sie mĂŒssen mit deren Versionen vorsichtig sein.
Der einfachste Weg, eine Bibliothek fĂŒr Arm zu erhalten, besteht darin, sie von einem ArbeitsgerĂ€t zu kopieren.
Referenzen
Hier ist der Quellcode fĂŒr das Beispiel. In diesem Repository sammelt die russischsprachige Gemeinschaft nach und nach Informationen, Beispiele und Links.
Hier finden Sie zusĂ€tzliche Informationen, z. B. zum Erstellen fĂŒr YoctoLinux.
Newsfeed in VK