How to write on D under ARM

3r33570. Good day, Habr! 3r33586. 3r3-3568.  
3r33570. Today I want to share my development experience for minicomputers on linux (RPI, BBB, and others) in the 3r339 programming language. D
. Under the cat, complete instructions on how to do it without pain. Well, or almost =) 3r38686. 3r3-3568.  
3r33570. How to write on D under ARM 3r33585. 3r3-3568.  
Why d? 3r33555. 3r3-3568.  
3r33570. When at work there was a task to write a monitoring system for ARM, even being a big fan of D, I wondered whether it was worth taking it as the main tool. In general, I am not a whimsical person, and D has been around for a long time, so I thought that it was worth a try and not so simple. On the one hand, there were no special problems (except for one that was not completely clear, which went away with the arrival of the new version of the compiler), on the other hand, people who develop ARM can constantly find that the toolkit is not completely ready for the word. You decide. 3r33586. 3r3-3568.  
Tooling 3r33555. 3r3-3568.  
3r33570. I can advise r3r3543. Visual Studio Code with plugin D Programming Language from comrade. WebFreak (Jan Jurzitza). In the settings you can set the 3r34343 setting. Beta Stream to always have the latest version of serve-d . The plugin itself installs the necessary software. 3r33586. 3r3-3568.  

The overall structure of the project 3r33555. 3r3-3568.  
3r33570. In general, it turned out quite confused (in comparison with the usual project on D), but, as it seems to me, it is quite flexible and convenient. 3r33586. 3r3-3568.  

  3r? 3543. .
Arm── arm-lib /
| Lib── libcrypto.a
| Lib── libssl.a
| Lib── libz.a
Do── docker-ctx /
| Cker── Dockerfile
| Entry──
3── source
| App── app.d
G── .gitignore
Build── build-docker
D── ddb
D── dub.sdl
L── ldc
Make── makefile 3r? 3531. 3r3-3568.  
3r33570. 3r? 3543. arm-lib - libraries required for the operation of our application (collected under the arm)
3r? 3543. docker-ctx - context to build docker image
3r? 3543. - will perform some actions on each launch of the container, about which later 3r33568.  
3r? 3543. dub.sdl - project file on D, allows you to include third-party libraries and more 3r33568.  
3r? 3543. build-docker - container assembly script (in fact, 1 line, but still)
3r? 3543. ddb - docker D builder - container launch script (just one line, but actually it’s more convenient)
3r? 3543. ldc - a script that allows you to call ldc with all the necessary parameters
3r? 3543. makefile - contains assembly recipes for arm and x86 and additional steps 3r33535.  
3r? 3543. source /app.d - sources of the project 3r3ir8686. 3r3-3568.  
3r33570. A few words about 3r34343. arm-lib . 3r3-3568.  
There are files needed for the vibe to work. Adding binary files to the repository is a bad form. But here to simplify your life it is easier to do just that. You can add them to the inside of the container, but then, to completely form the recipe for assembling the container, you will need to store the folder. arm-lib in 3r?343. dockert-ctx . The taste and color
3r3124. General assembly algorithm 3r33555. 3r3-3568.  
  3r? 3543. ./ddb make    3r? 3531. 3r3-3568.  
3r3185. 3r? 3543. ddb starts the container, executes the 3r34343 script. 3r3678.  
3r3185. 3r? 3543. tweaks a little 3r3r4343. dub 3r3444. so that the container will use the folder for libraries inside the container, which will be located in the current directory, which will allow you to not re-pump and collect the 3r3678 libraries used in the project when you restart the assembly.  
3r3185. 3r? 3543. ends with passing control to the input command (3r34343. make in our case) 3r3678.  
3r3185. 3r? 3543. make in turn, reads 3r33543. makefile 3r3678.  
3r3185. in 3r?343. makefile All flags for cross-compilation and directories for the assembly are stored, the call string 3r3-3543 is formed. dub 3r3444. 3r3678.  
3r3185. when calling in 3r34343. dub 3r3444. As a compiler, the script is passed to 3r33543. ldc from the current directory and set the environment variable  
3r3185. as a build dependency in 3r34343. makefile runtime libraries are exposed, which, when they are missing, are compiled by the program 3r33543. ldc-build-runtime 3r3678.  
3r3185. variables are passed to the 3r3r4343 script. ldc and in the parameters 3r34343. dub.sdl 3r3678.  
3r3192. 3r3-3568.  
3r3195. The contents of the main files 3r33555. 3r3-3568.  
3r-33199. Dockerfile 3r3-3568.  
3r33570. Since we will write under RPI? we select the image of the base system 3r34343. debian: stretch-slim there are 3r34343. gcc-arm-linux-gnueabihf uses the same version 3r3-34343. glibc as the official raspbian distribution (there was a problem with fedora, where the crosscompiler’s main filer used a too recent version of 3r34343. glibc ). 3r33586. 3r3-3568.  
  3r? 3543. 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 = ???
RUN wget -O /root/ldc.tar.xz$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"
RUN chmod + x /
WORKDIR /workdir
ENTRYPOINT["/" ]3r3544. 3r? 3531. 3r3-3568.  
3r33570. The compiler is 3r34343. ldc swinging from r3r3543. github where assembled based on the current 3r3-35433. llvm . 3r33586. 3r3-3568. 3r3–3500. 3r3-3568.  

  3r? 3543. #! /bin /bash
if[! -d ".dpack" ]; then
mkdir .dpack
ln -s $ (pwd) /. dpack /root/.dub
exec $ @ 3r? 3531. 3r3-3568.  
3r33570. Everything is simple: if there is no 3r34343 folder. .dpack , then create, use .dpack to create a symbolic link to r3r3543. /root/.dub . 3r3-3568.  
This will allow to keep downloaded dub 3r3444. th packages in the project folder. 3r33586. 3r3-3568.  

build-docker, ddb, ldc

3r33570. These are three simple single-line files. Two of them are optional, but convenient, but written for linux (bash). For windows, you will have to create similar files on the local script file or just run it by hand. 3r33586. 3r3-3568.  
3r33570. 3r? 3543. build-docker
starts the container assembly (it is called once, only for linux): 3r3-3568.  
  3r? 3543. #! /bin /bash
docker build -t dcross docker-ctx 3r? 3531. 3r3-3568.  
3r33570. 3r? 3543. ddb starts the container for the assembly and passes the parameters (only for linux): 3r3-3568.  
  3r? 3543. #! /bin /bash
docker run -v `pwd`: /workdir -t --rm dcross $ @ 3r? 3531. 3r3-3568.  
3r33570. Notice that the container name is dcross (the name itself is not important, but it must be the same in both files) and for forwarding the current directory to 3r34343. /workdir (the directory is specified as 3r34343. WORKDIR 3r3-35444. in 3r33543. Dockerfile 3r33535.) the command 3r?33543 is used. pwd (in win, it seems you need to use 3r3-33543.% CD% 3r3-33544.). 3r33586. 3r3-3568.  
3r33570. 3r? 3543. ldc launches 3r34343. ldc strangely enough, using environment variables (only linux, but runs in a container, so it doesn’t require a change to build under win): 3r33586. 3r3-3568.  
  3r? 3543. #! /bin /bash
$ LDC $ LDC_FLAGS $ @ 3r? 3531. 3r3-3568.  
3r33333. dub.sdl
3r33570. For example, it will be quite simple: 3r33586. 3r3-3568.  
  3r? 3543. name "chw"
description "Cross Hello World"
license "MIT"
targetType "executable"
targetPath "$ TP"
dependency "vibe-d" version = "~> ???"
dependency "vibe-d: tls" version = "~> ???"
subConfiguration "vibe-d: tls" "openssl-1.1" 3r? 3531. 3r3-3568.  
3r33570. 3r? 3543. targetPath is taken from the environment variable because dub 3r3444. some fields of the assembly recipe cannot be specified by platform (for example, 3r33543. lflags "-L.libs" platform = "arm" 3r33544. will add a flag to the linker only when assembled under the arm). 3r33586. 3r3-3568.  
3r33375. makefile 3r3-3568.  
3r33570. And here is the most interesting. Essentially 3r34343. make
not used for assembly as such, it calls for this 3r3-3543. dub 3r3444. , and already dub 3r3444. keeps track of what needs to be rebuilt and what is not. But using 3r34343. makefile all necessary environment variables are formed, additional commands are executed in more complex cases (building C libraries, packing update files, etc.). 3r33586. 3r3-3568.  
3r33570. Contents 3r34343. makefile more bulky rest: 3r3-3568.  
  3r? 3543. # By default, we collect under the arm
arch = arm
# target path - directory where binaries will be collected
TP = build - $ (arch)
LDC_DFLAGS = -mtriple = armv7l-linux-gnueabihf -disable-inlining -mcpu = cortex-a8
# tricky technique for replacing spaces with semicolons
LDC_BRT_DFLAGS = $ (subst $ (SPACE),;, $ (LDC_DFLAGS))
ifeq ($ (force), y)
# forcibly reassemble all packages even if
is built. # sometimes necessary because dub does not track some options for changes
FORCE = --force
FORCE = 3r3689. endif
ifeq ($ (release), y)
BUILD_TYPE = --build = release
DUB_FLAGS = build --parallel --compiler =. /Ldc $ (FORCE) $ (BUILD_TYPE)
$ (info DUB_FLAGS: $ (DUB_FLAGS))
# use path in container
LDC = ldc2
LDC_BRT = ldc-build-runtime
# ldc source directory where runtime libraries for ARM
will be built. LDC_RT_DIR = .ldc-rt
# use gcc here is only necessary for linking
GCC = arm-linux-gnueabihf-gcc
ifeq ($ (arch), x86)
else ifeq ($ (arch), arm)
LDC_FLAGS = $ (LDC_DFLAGS) -L-L./$(LDC_RT_DIR)/lib -L-L./arm-lib -gcc = $ (GCC)
$ (error unknown arch)
DUB = TP = $ (TP) LDC = $ (LDC) LDC_FLAGS = "$ (LDC_FLAGS)" dub $ (DUB_FLAGS)
# listed targets are not 3r3r968 files. .PHONY: all clean rtlibs stat
# default target
all: rtlibs
$ (DUB)
DRT_LIBS = $ (addprefix $ (LDC_RT_DIR) /lib /, libdruntime-ldc.a libdruntime-ldc-debug.a libphobos2-ldc.a libphobos2-ldc-debug.a)
CC = $ (GCC) $ (LDC_BRT) -j8 --dFlags = "$ (LDC_BRT_DFLAGS)" --buildDir = $ (LDC_RT_DIR) 3r3r968. --targetSystem = "Linux; UNIX" BUILD_SHARED_LIBS = OFF
# D runtime for ARM
rtlibs: $ (DRT_LIBS)
# You can count the number of lines of code
find source -name '* .d' | xargs wc -l
rm -rf $ (TP)
rm -rf .dub
$ (LDC_BRT) --buildDir = $ (LDC_RT_DIR) --resetOnly 3r? 3531.
3r33570. This 3r33543. makefile allows you to build a project both under the arm and under the x86 with almost one command: 3r3-3568.  
  3r? 3543. ./ddb make
./ddb make arch = x86 # collects in a container under x86
make arch = x86 # will compile on the host system in the presence of ldc 3r? 3531. 3r3-3568.  
3r33570. Files for arm go to build-arm , for x86 in build-x86 . 3r33586. 3r3-3568.  
3r3499. app.d 3r33500. 3r3-3568.  
3r33570. Well and on snack for the complete picture the code 3r3353543. app.d : 3r33586. 3r3-3568.  
  3r? 3543. 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", ""];
auto l = listenHTTP (settings, & handleRequest);
scope (exit) l.stopListening ();
runApplication ();
} 3r33544. 3r? 3531. 3r3-3568.  
3r33570. Everyone now needs a web =) 3r38686. 3r3-3568.  
3r33538. Conclusion 3r33555. 3r3-3568.  
3r33570. In general, everything is not so difficult as it seems at first glance, just a universal approach is not yet ready. Personally, I spent a lot of time trying to do without 3r33543. make . With him everything went somehow easier and more varied. 3r33586. 3r3-3568.  
3r33570. But you need to understand that D is not Go, it is customary to use external libraries in D and you need to be careful with their versions. 3r3-3568.  
The easiest way to get the library under the arm is to copy it from the working device. 3r33586. 3r3-3568.  
3r33554. References
3r33570. 3r3-3559. Here is 3r33585. source code example. In this repository, the Russian-speaking community gradually collects information, examples, links. 3r33586. 3r3-3568.  
3r33570. 3r33565. Here is 3r33585. There is more information, such as how to compile for YoctoLinux. 3r33586. 3r3-3568.  
3r33570. 3r33571. The news feed in VK 3r33585. 3r33586. 3r3690.
3r? 3577. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//"""_mediator") () (); 3r33578.
3r?383. Only registered users can participate in the survey. 3r33584. Log in 3r33585. , you are welcome. 3r33586.
3r? 3591.
3r? 3593. Have you tried D under the arm?
3r3673. Yes, I did everything, but in a different way
3r3673. Yes, I did everything the same
3r3673. Yes, but nothing happened
3r3673. No, but I want
3r3673. No
9 users have voted. Abstained 3 users. 3r3690.
+ 0 -

Add comment