https://wiki.dlang.org/api.php?action=feedcontributions&user=Johann+Lermer&feedformat=atom
D Wiki - User contributions [en]
2024-03-29T14:40:43Z
User contributions
MediaWiki 1.31.2
https://wiki.dlang.org/?title=Programming_in_D_tutorial_on_Embedded_Linux_ARM_devices&diff=9103
Programming in D tutorial on Embedded Linux ARM devices
2018-03-16T11:51:01Z
<p>Johann Lermer: fixed typo (populator -> popular)</p>
<hr />
<div>= Introduction =<br />
<br />
D is a great systems-programming language with clean syntax and great modelling power. Traditionally, Linux based embedded devices are programmed using C or C++. Python and Java are more popular today, but fail due to large runtime size and resource requirements. Programming in D will be comfortable, since it is like a dynamic language, but has native code performance, and has full ABI compatibility with C, making it very suitable as a “Linux systems-programming language”.<br />
<br />
This simple tutorial will introduce to programming in D on Embedded ARM Linux step by step.<br />
<br />
= Preparing your ARM GCC toolchain =<br />
<br />
The very first thing is to make your toolchain prepared. Although clang has supported ARM for a very long time, GCC is still the premier choice for compiling to ARM Linux systems.<br />
<br />
If you are a ARM Linux application programmer, you probably already have ARM GCC installed, and tested some hello world prgrams on your ARM board.<br />
<br />
However, if you haven't installed ARM GCC, it is quite easy.<br />
<br />
Arch Linux: <br />
<pre>$ pacman -S arm-linux-gnueabihf-gcc</pre><br />
Debian:<br />
<pre>$ apt install gcc-arm-linux-gnueabihf</pre><br />
<br />
After the toolchain installed, you need to make a simple test make sure that ARM GCC is generating arm executable properly.<br />
Create a file, test.c, that contains the following, using your favourite text editor.<br />
<br />
<syntaxhighlight lang="D"><br />
#include <stdio.h><br />
int main()<br />
{<br />
float a = 3.14;<br />
int b = 2;<br />
printf("hello world! 3.14 * 2 = %f\n";, a*b);<br />
return 0;<br />
}<br />
<br />
</syntaxhighlight><br />
Then compile using:<br />
<pre>$ arm-linux-gnueabihf-gcc test.c -o test</pre><br />
Copy the compiled program to your ARM target board:<br />
<pre>$ scp test user@armboard:/home/user</pre><br />
<br />
On the ARM target run the test executable.<br />
<pre>ARM $ ./test<br />
hello world! 3.14*2 = 6.280000<br />
</pre><br />
<div style="background:#ffd; padding: 0.5ex 0.5ex;"><br />
<span style="font-size: 1.4em; color: #ca4;">&#9888;</span>If your ARM GCC toolchain was compiled by yocto, you may need to call GCC using $CC after you sourced the environment setup script.<br />
</div><br />
<br />
= Installing LDC2 =<br />
<br />
D has 3 compiler implementations. Currently, only GDC and LDC support ARM and CPUs other than x86.<br />
<br />
GDC support for arm can be enabled if you are compiling your toolchain by yourself, by passing <code>–enable-languages=c,d,cpp</code> when configuring (i.e. <code>./configure -–enable-languages=c,d,cpp</code>. Or, you can download an ARM enabled GDC build from the [https://www.gdcproject.org/ GDC project home page].<br />
<br />
As of the writing of this tutorial, the latest GDC release (6.3.0) is not as good as LDC2, for ARM targets.<br />
<br />
LDC has better support for ARM targets, and is more actively developed that GDC. And, as it is based on LLVM, LDC does not need a cross-compiling toolchain prepared for an individual target.<br />
<br />
The recommended way to install LDC is by using the install script (works on POSIX and POSIX like systems):<br />
<pre>curl https://dlang.org/install.sh | bash -s ldc</pre><br />
<br />
You can also search your operating system's packages for the LDC package.<br />
<br />
Verify that LDC was installed correctly:<br />
<br />
<pre>$ ldc2 --version<br />
LDC - the LLVM D compiler (1.8.0):<br />
based on DMD v2.078.3 and LLVM 5.0.1<br />
built with LDC - the LLVM D compiler (1.8.0)<br />
Default target: x86_64-unknown-linux-gnu<br />
Host CPU: skylake<br />
http://dlang.org - http://wiki.dlang.org/LDC<br />
<br />
Registered Targets:<br />
aarch64 - AArch64 (little endian)<br />
aarch64_be - AArch64 (big endian)<br />
arm - ARM<br />
arm64 - ARM64 (little endian)<br />
......</pre><br />
As you can see from the ldc2 version output, arm64 is a registered target, but it’s not completely supported right now. It’s a little bit disappointing, but don’t worry, we have ARM well supported when the target is gcc+glibc+linux. And ARM and ARMhf executable can directly run on an arm64 target when arm64 has multilib support.<br />
<br />
= Compiling the D runtime for the ARM target =<br />
<br />
Before doing this, you need to make sure ,<code>cmake</code> is installed on your host. If not, please install it.<br />
Then, just type the commands bellow to compile your D runtime:<br />
<br />
<pre>$ CC=arm-linux-gnueabihf-gcc ldc-build-runtime --dFlags=&quot;-w;-mtriple=arm-linux-gnueabihf&quot; --targetSystem=&quot;Linux;UNIX&quot;<br />
-------------------------------------------------------------------<br />
Creating build directory: ldc-build-runtime.tmp<br />
Downloading LDC source archive: https://github.com/ldc-developers/ldc/releases/download/v1.8.0/ldc-1.8.0-src.zip<br />
Invoking: [&quot;cmake&quot;, &quot;-DLDC_EXE_FULL=/media/Devel/Changhong/IOT/imx6u-devel/toolchain/ldc2-1.8.0-linux-x86_64/bin/ldc2&quot;, &quot;-DD_VERSION=2&quot;, &quot;-DDMDFE_MINOR_VERSION=0&quot;, &quot;-DDMDFE_PATCH_VERSION=78&quot;, &quot;-DLDC_TARGET_PRESET=&quot;, &quot;-DTARGET_SYSTEM=Linux;UNIX&quot;, &quot;-DD_FLAGS=-w;-mtriple=arm-linux-gnueabihf&quot;, &quot;-DRT_CFLAGS=&quot;, &quot;-DLD_FLAGS=&quot;, &quot;/media/Devel/Changhong/IOT/imx6u-devel/toolchain/ldc2Armhf_runtime/ldc-build-runtime.tmp/ldc-src/runtime&quot;]<br />
......</pre><br />
The ldc-build-runtime tool will download ldc compiler source and making the build.<br />
<br />
'''''NOTE:''''' ''yocto built toolchain need to use a different manner:''<br />
<br />
<pre>CC=arm-poky-linux-gnueabi-gcc ldc-build-runtime --dFlags=&quot;-w;-mtriple=arm-poky-linux-gnueabi;-float-abi=hard;-mcpu=cortex-a7&quot; --targetSystem=&quot;Linux;UNIX&quot;</pre><br />
''for yocto toolchain the above arm-poky-linux-gnueabi-gcc is just a shell script adapter.''<br />
<br />
<pre>export SDKTARGETSYSROOT=your-target-root-fs-dir<br />
${POKYGCCBINPATH}/arm-poky-linux-gnueabi-gcc -march=armv7ve -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a7 --sysroot=$SDKTARGETSYSROOT $@</pre><br />
After the build, you will get something like bellow:<br />
<br />
<pre>$ ls <br />
ldc-build-runtime.tmp<br />
$ ls ldc-build-runtime.tmp/<br />
CMakeCache.txt cmake_install.cmake ldc-src lib objects objects-debug-shared<br />
CMakeFiles dummy.c ldc-src.zip Makefile objects-debug objects-shared</pre><br />
The runtime lib is sitting in <code>ldc-build-runtime.tmp/lib</code> , the directory named <code>ldc-build-runtime.tmp</code> is temporary, you can rename it to a <code>ldc_arm_runtime</code> or something you like.<br />
<br />
Then, we will make a simple alias for ease of use.<br />
<br />
<pre>alias ldcarm='ldc2 -mtriple=arm-linux-gnueabihf -gcc=arm-linux-gnueabihf-gcc -L=-L${LDC2ARMRUNTIME}/lib'</pre><br />
where <code>${LDC2ARMRUNTIME}</code> is the runtime directory you prepared earlier.<br />
<br />
= The D hello world on ARM =<br />
<br />
With your favourite text editor, just like before with c, make a file called test.d with your favourite text editor. It should contain the following code:<br />
<syntaxhighlight lang="D"><br />
import std.stdio;<br />
void main()<br />
{<br />
float a = 3.14;<br />
int b = 2;<br />
writeln("hello world from D!";);<br />
writeln("3.14 * 2 = ", a * b);<br />
}<br />
</syntaxhighlight><br />
<br />
Then compile the test program like this:<br />
<br />
<pre>ldcarm test.d -of testd</pre><br />
<code>-of</code> tells ldc to output the compiled executable with the file name <code>testd</code> instead of the default, which would derive the name from the input file.<br />
<br />
Now, copy the testd file you just created to your arm target, and take a deep breath before executing it.<br />
<br />
<pre>$ ./testd<br />
hello world from D!<br />
3.14 * 2 = 6.28</pre><br />
Wow! We finally reach the point! Congratulations!<br />
<br />
= Letting Dub manage the project =<br />
<br />
For testing, we will use dub to init a vibe.d hello world project.<br />
<br />
<pre>$ dub init vibeex --type=vibe.d<br />
Package recipe format (sdl/json) [json]: <br />
Name [vibeex]: <br />
Description [A simple vibe.d server application.]: <br />
Author name [dbh]: <br />
License [proprietary]: <br />
Copyright string [Copyright © 2018, dbh]: <br />
Add dependency (leave empty to skip) []: <br />
Successfully created an empty project in '/media/Devel/Changhong/IOT/imx6u-devel/project/vibeex'.<br />
Package successfully created in vibeex</pre><br />
The dub tool initialized a vibe.d example project, but the vibe.d dependency version is outdated. we need to tweak it. Edit the file <code>vibeex/dub.json</code> with your favourite text editor, changing the dependency version from <code>0.7.30</code> to <code>0.8.3</code>. The file should look something like this:<br />
<syntaxhighlight lang="json"><br />
{<br />
"name": "vibeex",<br />
"authors": [<br />
"dbh"<br />
],<br />
"dependencies": {<br />
"vibe-d": "~>0.8.30"<br />
},<br />
"description": "A simple vibe.d server application.",<br />
"copyright": "Copyright © 2018, dbh",<br />
"license": "proprietary"<br />
}<br />
</syntaxhighlight><br />
<br />
when building using dub, the alias we created (ldc-arm) will not work. We need to turn this into a shell script adapter:<br />
<br />
<syntaxhighlight lang="sh">#!/bin/sh<br />
LDC2ARMRUNTIME=/media/Devel/Changhong/IOT/imx6u-devel/toolchain/ldc2Armhf_runtime<br />
ldc2 -mtriple=arm-linux-gnueabihf -gcc=arm-linux-gnueabihf-gcc -L=-L${LDC2ARMRUNTIME}/lib $@<br />
</syntaxhighlight><br />
''for yocto toolchain, you will have an adapter like bellow:''<br />
<br />
<syntaxhighlight lang="sh"><br />
$ cat ldc-yocto-arm<br />
#!/bin/sh<br />
<br />
LDC2ARMRUNTIME=/media/Devel/Changhong/IOT/imx6u-devel/toolchain/ldc2Armhf_runtime<br />
ARMTARGETROOT=/media/Devel/Changhong/IOT/imx6u-devel/toolchain/yocto/targetroot<br />
ldc2 -mtriple=arm-poky-linux-gnueabi -float-abi=hard -mcpu=cortex-a7 -gcc=arm-poky-linux-gnueabi-gcc -L=-L${LDC2ARMRUNTIME}/lib -Xcc=--sysroot=$ARMTARGETROOT $@<br />
</syntaxhighlight><br />
'''NOTE''': if your toolchain does not have some library for the arm target present, dub will fail, with errors like this:<br />
<br />
Then compile the project using commands below:<br />
<br />
<pre>$ dub build --compiler=ldc-arm<br />
Performing &quot;debug&quot; build using ldc-arm for arm, arm_hardfloat.<br />
taggedalgebraic 0.10.9: building configuration &quot;library&quot;...<br />
eventcore 0.8.30: building configuration &quot;epoll&quot;...<br />
stdx-allocator 2.77.0: building configuration &quot;library&quot;...<br />
vibe-core 1.4.0: building configuration &quot;epoll&quot;...<br />
vibe-d:utils 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:data 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:crypto 0.8.3: building configuration &quot;library&quot;...<br />
diet-ng 1.4.5: building configuration &quot;library&quot;...<br />
vibe-d:stream 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:textfilter 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:inet 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:tls 0.8.3: building configuration &quot;openssl&quot;...<br />
vibe-d:http 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:mail 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:mongodb 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:redis 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:web 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d 0.8.3: building configuration &quot;vibe-core&quot;...<br />
vibeex ~master: building configuration &quot;application&quot;...</pre><br />
<br />
However, sometime we just get unlucky, and end up with something like this:<br />
<br />
<pre>$ dub build --compiler=ldc-arm<br />
Performing &quot;debug&quot; build using ldc-arm for arm, arm_hardfloat.<br />
taggedalgebraic 0.10.9: building configuration &quot;library&quot;...<br />
eventcore 0.8.30: building configuration &quot;epoll&quot;...<br />
stdx-allocator 2.77.0: building configuration &quot;library&quot;...<br />
vibe-core 1.4.0: building configuration &quot;epoll&quot;...<br />
vibe-d:utils 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:data 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:crypto 0.8.3: building configuration &quot;library&quot;...<br />
diet-ng 1.4.5: building configuration &quot;library&quot;...<br />
vibe-d:stream 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:textfilter 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:inet 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:tls 0.8.3: building configuration &quot;openssl&quot;...<br />
vibe-d:http 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:mail 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:mongodb 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:redis 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d:web 0.8.3: building configuration &quot;library&quot;...<br />
vibe-d 0.8.3: building configuration &quot;vibe-core&quot;...<br />
hellovibe ~master: building configuration &quot;application&quot;...<br />
/usr/lib/gcc-cross/arm-linux-gnueabihf/6/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lssl<br />
/usr/lib/gcc-cross/arm-linux-gnueabihf/6/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lcrypto<br />
/usr/lib/gcc-cross/arm-linux-gnueabihf/6/../../../../arm-linux-gnueabihf/bin/ld: cannot find -lz<br />
collect2: error: ld returned 1 exit status<br />
Error: /usr/bin/arm-linux-gnueabihf-gcc failed with status: 1<br />
ldc-arm failed with exit code 1.<br />
</pre><br />
This means that the library path does not include <code>libssl</code>, <code>libcrypto</code> and <code>libz</code>. You need to find or build a toolchain with the extra libraries built-in, or, just cross-compile the desired C library and install it to your toolchain's <code>sysroot</code> path.<br />
<br />
Let’s run the vibe.d example on arm target:<br />
<br />
<pre>root@armhost:~# ls -lh<br />
total 25M<br />
-rwxr-xr-x 1 root root 24M Mar 12 05:53 vibeex<br />
<br />
root@armhost:~# ./vibeex <br />
[main(----) INF] Listening for requests on http://[::1]:8080/<br />
[main(----) INF] Listening for requests on http://127.0.0.1:8080/<br />
[main(----) INF] Please open http://127.0.0.1:8080/ in your browser.<br />
Vibe was run as root, and no user/group has been specified for privilege lowering. Running with full permissions.</pre><br />
<br />
Yeah! we finally did it!</div>
Johann Lermer