Cómo escribir D en ARM

Buen dia, Habr!


Hoy quiero compartir mi experiencia de desarrollo para minicomputadoras en Linux (RPI, BBB y otras) en el lenguaje de programación D. Debajo del corte, instrucciones completas sobre cómo hacer esto sin dolor. Bueno, o casi ... =)



¿Por qué d?


Cuando en el trabajo, la tarea era escribir un sistema de monitoreo para ARM, incluso como un gran fanático de D, dudaba si debería ser tomado como la herramienta principal. En general, no soy una persona caprichosa, y he estado en D durante mucho tiempo, así que pensé que valía la pena intentarlo y ... no todo es tan simple. Por un lado, no hubo problemas especiales (a excepción de uno que no quedó del todo claro con la llegada de la nueva versión del compilador), por otro lado, las personas que se están desarrollando para ARM pueden pensar constantemente que el kit de herramientas no está listo para nada. Depende de usted.


Kit de herramientas


Puedo aconsejar a Visual Studio Code con el complemento D Programming Language de camaradas. WebFreak (Jan Jurzitza). En la configuración, puede establecer la configuración de Beta Stream para que siempre tenga la última versión de serve-d . El complemento mismo instala el software necesario.


Estructura general del proyecto.


En general, resultó bastante confuso (en comparación con el proyecto habitual en D), pero, según me parece, es bastante flexible y conveniente.


 . ├── 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 : bibliotecas necesarias para que nuestra aplicación funcione (compilada bajo arm)
docker-ctx : contexto para ensamblar una imagen de docker
entry.sh : realizará algunas acciones sobre cada lanzamiento posterior del contenedor, sobre el cual más tarde
dub.sdl : archivo de proyecto en D, le permite incluir bibliotecas de terceros y mucho más
build-docker : script de compilación del contenedor (esencialmente 1 línea, pero aún así)
ddb - docker D builder - script de inicio de contenedor (también una línea, pero en realidad más conveniente)
ldc : un script que le permite llamar a ldc con todos los parámetros necesarios
makefile : contiene recetas de compilación para arm y x86 y acciones adicionales
source/app.d - fuentes del proyecto


Algunas palabras sobre arm-lib .
Existen los archivos necesarios para que vibe funcione. Agregar archivos binarios al repositorio es una mala forma. Pero aquí, para simplificar tu vida, es más fácil hacer eso. Puede agregarlos dentro del contenedor, pero luego, para formar completamente la receta de ensamblaje del contenedor, deberá almacenar la carpeta arm-lib en dockert-ctx . El sabor y el color ...


Algoritmo de montaje general


 ./ddb make 

  1. ddb inicia el contenedor, ejecuta el script entry.sh
  2. entry.sh configura dub poco para que use la carpeta de la biblioteca dentro del contenedor, que se ubicará en el directorio actual, lo que le permitirá no bombear y recopilar las bibliotecas utilizadas en el proyecto cuando reinicie el ensamblaje
  3. entry.sh termina pasando el control al comando de entrada ( make en nuestro caso)
  4. a su vez lee makefile
  5. todos los indicadores para el directorio de compilación cruzada y compilación se almacenan en el makefile , se forma una línea de llamada de dub
  6. cuando se llama en dub script ldc del directorio actual se pasa como un compilador y se establecen variables de entorno
  7. Las bibliotecas de tiempo de ejecución se configuran como dependencias de maquillaje en el makefile , que, si faltan, son recogidas por el programa ldc-build-runtime
  8. las variables se pasan al script ldc y a los parámetros dub.sdl

El contenido de los archivos principales.


Dockerfile


Como escribiremos bajo RPI3, seleccionaremos la imagen del sistema debian:stretch-slim base debian:stretch-slim , donde gcc-arm-linux-gnueabihf usa la misma versión de glibc que la distribución oficial de raspbian (hubo un problema con fedora, donde el mantenedor del compilador cruzado usó una versión demasiado nueva de 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" ] 

El compilador ldc desde github , donde se compila en función del llvm actual.


entry.sh


 #!/bin/bash if [ ! -d ".dpack" ]; then mkdir .dpack fi ln -s $(pwd)/.dpack /root/.dub exec $@ 

Aquí todo es simple: si no hay .dpack carpeta .dpack , cree, use .dpack para crear un enlace simbólico a /root/.dub .
Esto le permitirá almacenar los paquetes descargados por el dub en la carpeta del proyecto.


build-docker, ddb, ldc


Estos son tres archivos simples de una sola línea. Dos de ellos son opcionales, pero convenientes, pero están escritos para Linux (bash). Para Windows, tendrá que crear archivos similares en el script local o simplemente ejecutarlo a mano.


build-docker inicia la compilación del contenedor (se llama una vez, solo para linux):


 #!/bin/bash docker build -t dcross docker-ctx 

ddb lanza el contenedor para el ensamblaje y pasa parámetros (solo linux):


 #!/bin/bash docker run -v `pwd`:/workdir -t --rm dcross $@ 

Tenga en cuenta que el nombre del contenedor se usa dcross (el nombre en sí mismo no importa, pero debe coincidir en ambos archivos) y el comando pwd se usa para Dockerfile directorio actual en /workdir (el directorio se especifica como WORKDIR en el Dockerfile ) (en win, parece que necesita usar %CD% ).


ldc inicia ldc , por extraño que parezca, mientras usa variables de entorno (solo linux, pero comienza en el contenedor, por lo que no es necesario cambiarlo para compilar en win):


 #!/bin/bash $LDC $LDC_FLAGS $@ 

dub.sdl


Por ejemplo, será bastante simple:


 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 se toma de la variable de entorno porque dub no puede especificar los campos de la receta de ensamblaje por plataforma (por ejemplo, lflags "-L.libs" platform="arm" agregará una bandera al enlazador solo cuando se construye bajo el brazo).


makefile


Y aquí está lo más interesante. De hecho, make no se usa para construir como tal, llama a un dub para esto, y el mismo dub monitorea lo que necesita ser reensamblado y lo que no. Pero con la ayuda de un makefile se forman todas las variables de entorno necesarias, se ejecutan comandos adicionales en casos más complejos (creación de bibliotecas en C, empaquetado de archivos de actualización, etc.).


El contenido del makefile más grande que el resto:


 #     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 

Tal makefile permite construir un proyecto bajo el brazo y x86 con casi un comando:


 ./ddb make ./ddb make arch=x86 #     x86 make arch=x86 #   host    ldc 

Los archivos para arm entran en build-arm , para x86 en build-x86 .


app.d


Bueno, para aperitivo, para la imagen completa, el código 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(); } 

Todos ahora necesitan web =)


Conclusión


En general, todo no es tan complicado como parece a primera vista, es solo que un enfoque universal aún no está listo. Personalmente, pasé mucho tiempo tratando de hacerlo sin make . Con él, todo fue de alguna manera más simple y más variado.


Pero debe comprender que D no es Go, en D es habitual utilizar bibliotecas externas y debe tener cuidado con sus versiones.
La forma más fácil de obtener una biblioteca para armar es copiarla desde un dispositivo que funcione.


Referencias


Aquí está el código fuente para el ejemplo. En este repositorio, la comunidad de habla rusa está recopilando gradualmente información, ejemplos, enlaces.


Aquí hay información adicional, como cómo compilar para YoctoLinux.


Feed de noticias en VK

Source: https://habr.com/ru/post/es428982/


All Articles