如何在ARM上编写D

美好的一天,哈伯!


今天,我想以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 

  1. ddb启动容器,执行entry.sh脚本
  2. entry.sh dub一些配置,以便它使用容器内的库文件夹,该文件夹位于当前目录中,这将使您在重新启动程序集时不会抽出并收集项目中使用的库
  3. entry.sh最终将控制权传递给输入命令(在本例中为make
  4. 依次读取makefile
  5. 所有用于交叉编译和构建目录的标志都存储在makefile ,形成了dub调用行
  6. 当调用dub当前目录中dub ldc脚本将作为编译器传递并设置环境变量
  7. 运行时库在makefile中设置为补充依赖项,如果缺少它们,则由ldc-build-runtime程序收集
  8. 变量被传递到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中的新闻提要

Source: https://habr.com/ru/post/zh-CN428982/


All Articles