こんにちは、Habr!
今日は、Linux上のミニコンピューター(RPI、BBBなど)の開発経験をDプログラミング言語で共有したいと思います。 カットの下で、痛みを伴わずにこれを行う方法に関する完全な指示。 まあ、またはほぼ... =)
なぜd?
仕事で、Dの大ファンであっても、ARMの監視システムを作成することがタスクであったとき、それをメインツールとして使用すべきかどうか疑問に思いました。 一般に、私は気まぐれな人ではなく、私は長い間Dにいるので、試してみる価値があると思った...すべてがそれほど単純ではない。 一方で、特別な問題はありませんでした(コンパイラーの新しいバージョンの到着で残された完全に明確な問題を除く)一方で、ARM向けに開発している人々は、ツールキットがその言葉にまったく対応していないと常に考えることができます。 それはあなた次第です。
ツールキット
同志のD Programming Language
プラグインを使用して、 Visual Studio Code
アドバイスできます。 WebFreak(Jan Jurzitza)。 設定では、常に最新バージョンのserve-d
を使用serve-d
ようにBeta Stream
設定を設定できます。 プラグイン自体が必要なソフトウェアをインストールします。
プロジェクトの一般的な構造
一般的に、(Dの通常のプロジェクトと比較して)非常に混乱していることが判明しましたが、私には思えるように、非常に柔軟で便利です。
. ├── 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
アプリケーションが動作するために必要なライブラリ(アームの下でコンパイル)
docker-ctx
-Dockerイメージを組み立てるためのコンテキスト
entry.sh
後でコンテナを起動するたびにいくつかのアクションを実行します。
dub.sdl
-Dのプロジェクトファイル。サードパーティライブラリなどを含めることができます。
build-docker
コンテナビルドスクリプト(基本的に1行ですが、それでも)
ddb
- ddb
D ddb
コンテナ起動スクリプト(1行ですが、実際はより便利です)
ldc
必要なすべてのパラメーターを指定してldcを呼び出すことができるスクリプト
makefile
-armおよびx86のビルドレシピと追加のアクションが含まれています
source/app.d
プロジェクトソース
arm-lib
について一言。
vibeが機能するために必要なファイルがあります。 リポジトリにバイナリファイルを追加することはお勧めできません。 しかし、ここではあなたの人生を単純化するためにそれをする方が簡単です。 コンテナ内に追加できますが、コンテナアセンブリレシピを完全に形成するには、 arm-lib
フォルダをdockert-ctx
に保存する必要があります。 味と色...
一般的なアセンブリアルゴリズム
./ddb make
-
ddb
はコンテナを起動し、entry.sh
スクリプトを実行します -
entry.sh
は、現在のディレクトリにあるコンテナ内のライブラリフォルダーを使用するようにdub
少し構成します。これにより、アセンブリを再起動するときにプロジェクトで使用されるライブラリを再起動し、収集できなくなります。 -
entry.sh
は、入力コマンドに制御を渡します(この例ではmake
)。 -
make
はmakefile
を読み取ります - クロスコンパイルとビルドディレクトリのすべてのフラグは
makefile
に保存され、dub
コールラインが形成されます -
dub
呼び出されると、現在のディレクトリのldc
スクリプトがコンパイラとして渡され、環境変数が設定されます - 実行時ライブラリは、
makefile
内のmakefile
アップ依存関係として設定され、見つからない場合、ldc-build-runtime
プログラムによって収集されldc-build-runtime
- 変数は
ldc
スクリプトとdub.sdl
パラメーターにdub.sdl
ます
メインファイルの内容
Dockerfile
RPI3で記述するため、ベースのdebian:stretch-slim
システムのイメージを選択しますdebian:stretch-slim
、 gcc-arm-linux-gnueabihf
は公式のraspbianディストリビューションと同じバージョンのglibc
を使用します(クロスコンパイラメンテナーがあまりにも新しいバージョンの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" ]
ldc
コンパイラーは、現在のllvm
基づいてコンパイルされるgithub
からldc
。
entry.sh
#!/bin/bash if [ ! -d ".dpack" ]; then mkdir .dpack fi ln -s $(pwd)/.dpack /root/.dub exec $@
ここではすべてが簡単です.dpack
フォルダーがない場合は、作成し、 .dpack
を使用して.dpack
へのシンボリックリンクを作成します。
これにより、 dub
によってダウンロードされたパッケージをプロジェクトフォルダーに保存できます。
build-docker、ddb、ldc
これらは3つの単純な単一行ファイルです。 そのうちの2つはオプションですが、便利ですが、Linux(bash)用に作成されています。 Windowsの場合、同様のファイルをローカルスクリプトに作成するか、手動で実行する必要があります。
build-docker
はコンテナアセンブリを開始します(1回だけ呼び出され、Linuxのみ):
#!/bin/bash docker build -t dcross docker-ctx
ddb
はアセンブリ用のコンテナを起動し、パラメータを渡します(Linuxのみ):
#!/bin/bash docker run -v `pwd`:/workdir -t --rm dcross $@
コンテナ名はdcross
で使用され(名前自体は重要ではありませんが、両方のファイルで一致する必要があります)、 pwd
コマンドを使用して/workdir
現在のディレクトリをDockerfile
ます(ディレクトリはWORKDIR
でDockerfile
として指定されます)(winでは、 %CD%
を使用する必要があるようです) %CD%
)。
ldc
は、環境変数を使用しながら、奇妙なことにldc
起動します(Linuxのみですが、コンテナで起動するため、winでビルドするために変更する必要はありません)。
#!/bin/bash $LDC $LDC_FLAGS $@
dub.sdl
たとえば、それは非常に簡単です:
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
は環境変数から取得されます。これは、 dub
がプラットフォームlflags "-L.libs" platform="arm"
アセンブリレシピの一部のフィールドを指定できないためです(たとえば、 lflags "-L.libs" platform="arm"
は、腕の下でビルドする場合にのみリンカーにフラグを追加します)。
メイクファイル
そして、ここが最も興味深いものです。 実際、 make
そのようなビルドには使用されず、このためにdub
を呼び出し、 dub
自体が再構築する必要があるものとしないものを監視します。 しかし、 makefile
の助けを借りて、必要なすべての環境変数が形成され、より複雑なケースで追加のコマンドが実行されます(Cでのライブラリの構築、更新ファイルのパッキングなど)。
makefile
の内容は、他のmakefile
よりも大きくなっています。
# 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
このようなmakefile
使用すると、ほとんど1つのコマンドでarmとx86の両方でプロジェクトをビルドできます。
./ddb make ./ddb make arch=x86 # x86 make arch=x86 # host ldc
build-x86
場合、 build-arm
ファイルはbuild-arm
に入ります。
app.d
まあ、前菜、全体像、 app.d
コード:
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(); }
誰もが今ウェブを必要としています=)
おわりに
一般に、すべてが一見したほど複雑ではなく、普遍的なアプローチがまだ準備されていないというだけです。 個人的には、 make
なしでやろうとして多くの時間を費やしました。 彼と一緒に、すべてが何らかの形でよりシンプルでより多様になりました。
ただし、DはGoではないことを理解する必要があります。Dでは、外部ライブラリを使用するのが一般的であり、それらのバージョンに注意する必要があります。
arm用のライブラリを取得する最も簡単な方法は、動作中のデバイスからライブラリをコピーすることです。
参照資料
例のソースコードを次に示します。 このリポジトリでは、ロシア語を話すコミュニティが徐々に情報、例、リンクを収集しています。
ここには、YoctoLinux用にビルドする方法などの詳細情報があります。