2020-05-31 RG350 Compilar aplicaciones

OpenDingux logo

En el post anterior vimos cómo construir un entorno para hacer compilación cruzada para el procesador y el sistema operativo de la RG350. En este post separado vamos a ver cómo utilizar el entorno anterior para compilar algunos programas.

Aclarar que este entorno es necesario para compilar código en C y C++ que es el habitual en sistemas embebidos Linux. Puede haber programas pensados para la RG350 que estén programados en otros lenguajes. Por ejemplo el frontend PyMenu está programado en Python. En ese caso no necesitamos un compilador; en todo caso algunas herramientas como el empaquetador de OPK para montar el instalador de PyMenu, pero no el compilador.

Por supuesto el toolchain será imprescindible para construir una imagen completa para la consola. En el post anterior ya se relataron los pasos para realizar esta operación. En este artículo vamos a centrarnos en la compilación de aplicaciones, ya que tiene su propia complejidad. Uno de los problemas del ambiente C es que existen multitud de gestores de compilación que además se pueden utilizar de múltiples formas, por lo que será habitual que cada aplicación se compile de una forma particular. Aquí vamos a ver algunos ejemplos habituales.

En el post anterior se comenta que el toolchain, una vez compilado queda en el directorio ~/git/RG350_buildroot/output/host/usr/bin. Si listamos el contenido de ese directorio veremos muchos binarios y otros tantos enlaces simbólicos para que algunos de los binarios tengan nombres habituales. Uno de los más importantes es el binario toolchain-wrapper que adopta múltiples nombres a través de los enlaces simbólicos:

$ ls -l |fgrep toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-c++ -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-cc -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-cpp -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-g++ -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-gcc -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-gcw0-linux-uclibc-gcc-5.4.0 -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-c++ -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-cc -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-cpp -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-g++ -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-gcc -> toolchain-wrapper
lrwxrwxrwx 1 root root      17 may 29 00:19 mipsel-linux-gcc-5.4.0 -> toolchain-wrapper
-rwxr-xr-x 1 root root   14808 may 29 00:19 toolchain-wrapper

Como vemos, encontramos ahí todos los nombres habituales del compilador de C y C++ para Linux sobre arquitectura MIPS.

Veamos pues algunos ejemplos de compilación de distintos programas.

invoker

Se trata de un pequeño programa utilizado por el frontend SimpleMenu para ejecutar los emuladores. El código de invoker se encuentra en este repositorio. Analizando los ficheros vemos que el proyecto tiene ya hecho un sencillo Makefile. Al ser un programa muy pequeño y simple resulta muy educativo. Tampoco tiene dependencias con ninguno de los paquetes de Buildroot por lo que no será necesario compilar antes ninguno de ellos, tan sólo el toolchain. Vamos a ver cómo compilarlo con nuestro recien construido toolchain paso a paso:

  1. Bajamos el código dentro del directorio git de la máquina host que es el que tenemos conectado con el contenedor:

    $ cd ~/git
    $ git clone https://github.com/fgl82/invoker.git
    
  2. Editamos el fichero /git/invoker/invoker/Makefile. Cambiamos el parámetro PLATFORM en las primeras lineas para que sea RG-350 y corregimos la ruta del compilador de nuestro toolchain en la linea 16:

    ...
    else ifeq ($(PLATFORM), RG-350)
      CC = /root/git/RG350_buildroot/output/host/usr/bin/mipsel-gcw0-linux-uclibc-gcc
    ...
    
  3. Conectamos con el contenedor:

    $ docker start RG350_buildroot
    $ docker exec -it RG350_buildroot /bin/bash
    
  4. Compilamos:

    # cd ~/git/invoker/invoker
    # make
    

Veremos los mensajes del compilador y al terminar encontraremos dos nuevos binarios:

root@18c6ecd1a610:~/git/invoker/invoker# ls -ltr
total 36
-rw-rw-r-- 1 1000 1000  4844 May 30 20:21 invoker.c
-rw-rw-r-- 1 1000 1000  1685 May 30 20:27 Makefile
-rw-r--r-- 1 root root 14368 May 30 20:28 invoker.o
-rwxr-xr-x 1 root root  5484 May 30 20:28 invoker.dge

Tetris Clone for the RG350

Continuamos con un port de un juego. El código podemos encontrarlo aquí. Analizando los ficheros vemos que el proyecto es de tipo CMake. Vamos a ver cómo se podría compilar:

  1. Bajamos el código:

    $ cd ~/git
    $ git clone https://github.com/eduardofilo/tetris_rg350.git
    
  2. Editamos fichero ~/git/tetris_rg350/CMakeLists.txt para ajustar las rutas del toolchain de esta forma:

    SET(CMAKE_C_COMPILER   "/root/git/RG350_buildroot/output/host/usr/bin/mipsel-gcw0-linux-uclibc-gcc")
    SET(CMAKE_CXX_COMPILER "/root/git/RG350_buildroot/output/host/usr/bin/mipsel-gcw0-linux-uclibc-g++")
    SET(CMAKE_RANLIB "/root/git/RG350_buildroot/output/host/usr/bin/mipsel-gcw0-linux-uclibc-ranlib")
    SET(CMAKE_LINKER "/root/git/RG350_buildroot/output/host/usr/bin/mipsel-gcw0-linux-uclibc-ld")
    SET(CMAKE_FIND_ROOT_PATH  /root/git/RG350_buildroot/output/host/usr/mipsel-gcw0-linux-uclibc/sysroot)
    
  3. La forma en la que están construidos los ficheros CMakeLists.txt exige que la versión de cmake a utilizar sea igual o superior a la 3.13, pero nosotros tenemos 3.7. Por tanto es necesario hacer modificaciones en los CMakeLists.txt. Comentamos la última línea del fichero ~/git/tetris_rg350/CMakeLists.txt:

    #install(TARGETS tetris RUNTIME DESTINATION ${BIN_DIR} )
    
  4. Y descomentamos la última linea del ~/git/tetris_rg350/src/CMakeLists.txt:

    install(TARGETS tetris RUNTIME DESTINATION ${BIN_DIR} )
    
  5. Conectamos con el contenedor que contiene el toolchain:

    $ docker start RG350_buildroot
    $ docker exec -it RG350_buildroot /bin/bash
    
  6. El programa tiene 4 paquetes como dependencias, así que los tenemos que compilar previamente. Si es la primera vez tardará bastante:

    # cd ~/git/RG350_buildroot
    # export BR2_JLEVEL=0
    # make sdl2 sdl2_image sdl2_mixer sdl2_ttf
    
  7. Finalmente compilamos el programa (el binario resultante de la compilación queda en ~/git/tetris_rg350/build/tetris):

    # cd ~/git/tetris_rg350
    # mkdir bin
    # cd ~/git/tetris_rg350/build
    # cmake ..
    # make
    
  8. Sólo queda empaquetar el binario y sus recursos (gráficos, sonidos, fichero .desktop para el lanzador, etc.). Existe un pequeño script que lo hace por nosotros, así que lo utilizamos:

    # cd ~/git/tetris_rg350/build
    # ./make_opk.sh
    

Si todo ha ido bien el OPK resultante se encontrará en ~/git/tetris_rg350/build/tetris.opk. Comentar que por ejemplo el OPK compilado de esta forma no es operativo en ROGUE (seguramente por las diferencias en las versiones de las librerías SDL). Sin embargo en la imagen de sistema compilada con este mismo Buildroot funciona correctamente.

DinguxCmdr

En esta ocasión vamos a compilar una aplicación de uso frecuente, el DinguxCommander o DinguxCmdr. Las fuentes las podemos encontrar en este repositorio. Analizando su contenido vemos que ofrece un script para automatizar la compilación, aunque internamente se trata de un proyecto de tipo CMake. El procedimiento para compilarlo es:

  1. Bajamos el código:

    $ cd ~/git
    $ git clone https://github.com/od-contrib/commander.git
    
  2. Conectamos con el contenedor que contiene el toolchain:

    $ docker start RG350_buildroot
    $ docker exec -it RG350_buildroot /bin/bash
    
  3. Definimos la variable de entorno que servirá para localizar el toolchain de nuestro Buildroot:

    # export BUILDROOT=/root/git/RG350_buildroot
    
  4. Ejecutamos el script indicando la plataforma de destino:

    # cd ~/git/commander
    # ./build.sh rg350
    

Tras terminar encontraremos el OPK en ~/git/commander/build-rg350/commander-rg350.opk. Al igual que ocurre con Tetris Clone for the RG350 el OPK no es operativo en ROGUE. Sin embargo en la imagen de sistema compilada con este mismo Buildroot funciona correctamente.