美好的一天,哈伯!
今天,我想以D编程语言分享我在Linux上的微型计算机(RPI,BBB等)的开发经验。 在切口下,完整说明如何无痛操作。 好吧,或几乎... =)

为什么D?
在工作时,即使是D的忠实拥护者,任务还是要为ARM编写一个监视系统,我怀疑它是否应该作为主要工具。 总的来说,我不是一个异想天开的人,而且我在D上待了很长时间,所以我认为值得一试,而且...并非所有事情都那么简单。 一方面,没有特殊的问题(除了一个不完全清楚的问题,这是随着新版本的编译器的到来而产生的),另一方面,为ARM开发的人可以不断地认为该工具包根本不适合这个词。 由您决定。
工具包
我可以使用同志的D Programming Language
插件来建议Visual Studio Code
。 WebFreak(Jan Jurzitza)。 在设置中,您可以将Beta Stream
设置设置为始终具有serve-d
的最新版本。 该插件本身会安装必要的软件。
项目总体结构
总的来说,它看上去很混乱(与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
我们的应用程序运行所需的库(在arm下编译)
docker-ctx
组装docker映像的上下文
entry.sh
将在以后每次启动容器时执行一些操作,稍后执行
dub.sdl
-D中的项目文件,允许您包含第三方库等
build-docker
容器构建脚本(基本上是1行,但仍然)
ddb
-docker D ddb
容器启动脚本(也是一行,但实际上更方便)
ldc
一个脚本,可让您使用所有必要的参数调用ldc
makefile
包含arm和x86的构建配方以及其他操作
source/app.d
项目来源
关于arm-lib
几句话。
有些文件需要振动才能正常工作。 将二进制文件添加到存储库是错误的形式。 但是在这里,为了简化您的生活,做到这一点更加容易。 您可以将它们添加到容器中,但是,为了完全形成容器组装配方,您需要将arm-lib
文件夹存储在dockert-ctx
。 味道和颜色...
通用装配算法
./ddb make
ddb
启动容器,执行entry.sh
脚本entry.sh
dub
一些配置,以便它使用容器内的库文件夹,该文件夹位于当前目录中,这将使您在重新启动程序集时不会抽出并收集项目中使用的库entry.sh
最终将控制权传递给输入命令(在本例中为make
)- 依次读取
makefile
- 所有用于交叉编译和构建目录的标志都存储在
makefile
,形成了dub
调用行 - 当调用
dub
当前目录中dub
ldc
脚本将作为编译器传递并设置环境变量 - 运行时库在
makefile
中设置为补充依赖项,如果缺少它们,则由ldc-build-runtime
程序收集 - 变量被传递到
ldc
脚本和dub.sdl
参数
主文件的内容
Docker文件
由于我们将在RPI3下编写代码,因此我们选择了基本的debian:stretch-slim
系统的图像debian:stretch-slim
,其中gcc-arm-linux-gnueabihf
使用的glibc
版本与正式的raspbian发行版相同(fedora出现了问题,交叉编译器维护程序使用的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
编译器从github
ldc
,它是根据当前llvm
编译的。
entry.sh
#!/bin/bash if [ ! -d ".dpack" ]; then mkdir .dpack fi ln -s $(pwd)/.dpack /root/.dub exec $@
这里的一切都很简单:如果没有.dpack
文件夹,则可以创建,使用.dpack
创建指向/root/.dub
的符号链接。
这将使您可以将dub
下载的软件包存储在项目文件夹中。
构建docker,ddb,ldc
这是三个简单的单行文件。 其中两个是可选的,但很方便,但是是为linux(bash)编写的。 对于Windows,您将不得不在本地脚本上创建类似的文件,或者只是手动运行它。
build-docker
启动容器构建(仅针对linux调用一次):
#!/bin/bash docker build -t dcross docker-ctx
ddb
启动用于汇编的容器并传递参数(仅linux):
#!/bin/bash docker run -v `pwd`:/workdir -t --rm dcross $@
请注意,容器名称用于dcross
(名称本身并不重要,但必须在两个文件中都匹配),并且pwd
命令用于Dockerfile
/workdir
Dockerfile
当前目录(该目录在Dockerfile
指定为WORKDIR
)(在win中,看来,您需要使用%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
无法按平台指定组装配方的字段(例如,仅当在arm下构建时, lflags "-L.libs" platform="arm"
才会向链接器添加一个标志)。
生成文件
这是最有趣的。 实际上, make
并不像这样用于构建,它为此调用了一个dub
,并且dub
本身监视需要重新组装的内容以及不需要重新组装的内容。 但是借助makefile
可以形成所有必要的环境变量,在更复杂的情况下(在C中构建库,打包更新文件等)可以执行其他命令。
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
允许您使用几乎一个命令在arm和x86下构建项目:
./ddb make ./ddb make arch=x86 # x86 make arch=x86 # host ldc
用于arm的文件进入build-arm
x86中用于x86的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(); }
现在每个人都需要网络=)
结论
总的来说,一切并不像乍看起来那样复杂,只是通用方法尚未准备好。 就个人而言,我花了很多时间尝试不做。 和他在一起,一切都变得更加简单和多样化。
但是您需要了解D不是Go,在D中习惯于使用外部库,因此您必须小心其版本。
获取库的最简单方法是从工作设备复制它。
参考文献
这是示例的源代码。 在这个知识库中,俄语社区正在逐渐收集信息,示例,链接。
这里还有其他信息,例如如何为YoctoLinux构建。
VK中的新闻提要