最近自己开发一个板子上的数据处理与转发。无需UI,本来都是基于Qt/C++进行板子开发的。但是不同型号和板子基本都是靠厂商的虚拟机开发。于是想到之前用Dlang支持交叉编译的,于是测试了下Dlang下ARM嵌入式开发,结果让人惊喜。十分愉快。
Dlang进行ARM开发基于LDC,可以选择完全betterC或完整D语言。本次小项目考虑周边的库,就采用的完整D语言开发的方案。至于GC,作为一个安全的内存池使用。
开发依赖:
- Linux 主机,因为基本ARM交叉编译GCC都是linux运行的,我是在 openSUSE-Tumbleweed下
- LDC 编译器,dmd不支持arm,需要使用LDC
- arm-gcc 交叉编译器(开发板厂家会提供,只需要C语言编译器就行。)
开发步骤:
- 交叉编译 DRuntime 和 Phobos
- 配置LDC交叉编译的依赖库和链接器(GCC)
- 使用D语言编写程序(注意依赖,如果依赖需要C库,相应库也需要交叉编译)
- 进行交叉编译程序(dub build –compiler=ldc2 –arch=你的交叉编译配置)
我的环境
下面指令和命令都是基于我的环境构建,先把我的环境公布,剩下指令更改,根据环境不同自己变更。
主机环境
LDC位置
LDC放在用户 bin 目录下。使用链接需要的dub与ldc2到~/bin下。在openSUSE下,~/bin也会添加到PATH中。省下设置PATH那一步了。
交叉编辑器
交叉编译器,按照开发板资料部署。本次是放到的目录中,并执行 设置脚本。
1.交叉编译 DRuntime 和 Phobos
ldc交叉编译 DRuntime 和 Phobos 十分方便,提供了工具。如果下载代码中断,可以自己手动下载代码,放置到目录中。
需要安装CMAKE或ninja构建系统。在此我是使用了 ninja 构建系统。
编译命令:
CC=/home/duyu/bin/arm/arm-huiwei-linux-gnueabihf_sdk-buildroot/bin/arm-linux-gcc ldc-build-runtime --ninja --dFlags="-mtriple=arm-linux-gnueabihf"
- 其中 CC 是设置交叉编译器环境
- ldc-build-runtime –ninja 使用ldc提供的 编译命令,此命令在 ldc的bin目录下,使用 ninja构建系统构建
- –dFlags="-mtriple=arm-linux-gnueabihf" 设置交叉编译参数。arm 平台,linux系统,gnueabihf 是 arm下 float软解还是硬解参数,应该和交叉编译器后缀一样。
执行这个命令,会自动下载ldc的源码,并在执行的目录生成编译的临时目录。(自动下载比较慢,可以自己手动下载,然后按照下载名字命名)。
执行完成后,会生成 lib 目录,就是我们交叉编译出来的目标平台(ARM-LINUX)下的 D 运行时与标准库了。
然后把库复制到 LDC 目录下,重命名自己标识的名字。例如我的重命名为了 “lib_huiweiArm”,是以开发板厂家命名的。
2.配置LDC交叉编译环境
更改 ldc 目录下 etc/ldc2.conf ,添加我们目标平台的编译配置。
例如我的配置:
上面是名字配置:格式是 "平台-平台备注-系统-系统备注"(后面两个备注都不是必须)
例如我的配置:arm-huiwei-linux-gnueabihf,其中 arm,linux,gnueabihf都是必须配置,huiwei可以使用 ".*" 用来所有的arm-linux平台使用,我加上huiwei是为了区别以后其他板子。
下面配置是JSON格式。其中:
- switches 是传给编译器(LDC2)的参数。这里配置了 默认依赖的运行时库,以及使用的交叉编译gcc(这个必须配置,链接需要交叉编译的链接器)。
- lib-dirs 库目录,也就是我们交叉编译出来 运行时的目录。这里也可以添加 板子环境中提供的库目录,或以来其他C的库(交叉编译后的)的目录。
- rpath 默认defaultlib库的目录,也就是我们我们交叉编译出来 运行时的目录。
我们根据实际情况填写我们交叉编译出来的库和信息。
3.编写我们的D程序
这里使用 dub 生成和更改我们的程序。这里生成一个http的tcp echo server。
- dub.json 注意这里使用vibe.d设置不支持ssl,因为vibe.d的ssl需要openssl,板子环境里没有。
{ "authors": [ "duyu" ], "copyright": "Copyright © 2023, duyu", "dependencies": { "serialport": "~>2.2.3", "vibe-d:http": "~>0.9.7", "vibe-d:tls": "~>0.9.7", "yu" :{ "path" : "../yu" } }, "description": "A simple vibe.d server application.", "license": "proprietary", "name": "webApi", "subConfigurations": { "vibe-d:tls": "notls" } }
- app.d 主要程序,实现一个http的hello word以及 tcp echo server
import vibe.http.server; import vibe.http.router; import vibe.core.net; import vibe.core.core; import vibe.core.stream; import vibe.core.log; import vibe.http.router; void main() { auto settings = new HTTPServerSettings; settings.port = 8080; auto router = new URLRouter(); router.any("/",&hello); auto listener = listenHTTP(settings, router); auto tcps = listenTCP(2000, (conn) { try conn.pipe(conn); catch (Exception e) conn.close(); }); scope (exit) { listener.stopListening(); foreach (ref k;tcps){ k.stopListening(); } } logInfo("Please open http://127.0.0.1:8080/ in your browser."); runApplication(); } void hello(HTTPServerRequest req, HTTPServerResponse res) { res.writeBody("Hello, World!"); }
4. 交叉编译我们的程序
使用dub交叉编译我们程序,命令:
dub build --compiler=ldc2 --arch=arm-huiwei-linux-gnueabihf
- –compiler=ldc2 使用 ldc2编译器,dmd不支持交叉编译
- –arch=arm-huiwei-linux-gnueabihf 设置目标平台,配置就是我们ldc2.conf内设置的名字。
如果需要 release 还需要在后面添加 “-b release”dub build --compiler=ldc2 --arch=arm-huiwei-linux-gnueabihf -b release
结尾
把 我们交叉编译的程序通过 sftp/ftp等传输到板子上,然后
chmod +x ./webApi”
添加可执行权限。然后就可以启动运行了。
这样编译,D 语言的所有依赖均是 静态编译,但是依赖 libc等库,如果需要完全静态编译,可以在了ldc2.conf中,我们的配置“switches”下,添加 “–static” 选项。
参考资料:
[1]Cross-compiling with LDC
[2]Building LDC runtime libraries
转载请注明:来自 “渡世白玉” https://www.dushibaiyu.com/
Dear author,
Recently discovered your blog by searching for posts about Dlang.
I liked your analyzes about D & ldc2 (mainly), and I don’t know if the tool offers any technical clarification on compiler-ABI usage.
It is clear that it is possible to rule out the use of EH-ABI (nothrow) (use libgcc_s/libunwind?) and betterC. However, what about libgcc or libcompiler-rt support?
Sorry, but I wonder about these internal topics because as a systems developer this subject is very obscure.
I believe you will agree with me that the native integration of the development environment is aimed at the mainstream (gnu/msvc) specific to each platform. Rust, D,C/C++, etc… follow this line.
However, languages like Zig (lang &toolchain) that propose to offer only their own solution (toolchain self-contained) can leave inexperienced users confused by leaving their comfort zone.
e.g.: zig c++ build cpp code static-linking (libc++ + libunwind + compile-rt) on any (except, msvc yet) LLVM triple-targets. Non-GNU? Maybe choiced musl on Linux, but mingw/gnu (glibc [universal-headers] switching version) is allowed too.
ldc2+zig cross-compile:
https://gist.github.com/kassane/2a181fa4dfe66dbd283f3ad7a941ca2b