ARMでDを書く方法

こんにちは、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 

  1. ddbはコンテナを起動し、 entry.shスクリプトを実行します
  2. entry.shは、現在のディレクトリにあるコンテナ内のライブラリフォルダーを使用するようにdub少し構成します。これにより、アセンブリを再起動するときにプロジェクトで使用されるライブラリを再起動し、収集できなくなります。
  3. entry.shは、入力コマンドに制御を渡します(この例ではmake )。
  4. makemakefileを読み取ります
  5. クロスコンパイルとビルドディレクトリのすべてのフラグはmakefileに保存され、 dubコールラインが形成されます
  6. dub呼び出されると、現在のディレクトリのldcスクリプトがコンパイラとして渡され、環境変数が設定されます
  7. 実行時ライブラリは、 makefile内のmakefileアップ依存関係として設定され、見つからない場合、 ldc-build-runtimeプログラムによって収集されldc-build-runtime
  8. 変数はldcスクリプトとdub.sdlパラメーターにdub.sdlます

メインファイルの内容


Dockerfile


RPI3で記述するため、ベースのdebian:stretch-slimシステムのイメージを選択しますdebian:stretch-slimgcc-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ます(ディレクトリはWORKDIRDockerfileとして指定されます)(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用にビルドする方法などの詳細情報があります。


VKのニュースフィード



Source: https://habr.com/ru/post/J428982/


All Articles