¿Por qué?
"Just for the fun of it". Bueno, puede haber razones mejores, como no poder encontrar un compilador adaptado a la distribución en la que queremos trabajar, por necesitar alguna herramienta de debug que no facilita la toolchain oficial... o simplemente como excusa para familiarizarnos con algunas de las características de la raspberry.En todo caso el proceso que se describe aquí sirve para crear con relativa facilidad un crosscompilador, especialmente para la arquitectura ARM.
Generar la toolchain
La toolchain puede construirse con ayuda de la herramienta crosstool-ng, disponible en: http://crosstool-ng.org/
Instalación de croostol-ng
Nos descargamos la última versión y la descomprimimos:
tar -xvf crosstool-ng-1.18.0.tar.bz2
El paquete sigue la estructura de las autotools, así que pasito a pasito:
Si no las tenemos instaladas: sudo apt-get install automake autoconf libtool
Finalizada la instalación ejecutar todos los pasitos (en la versión que me he descargado algunos pasos, como autoheader no son necesarios. Pero pueden ser necesarios en otras versiones, así que mejor ejecutarlos todos :) )
aclocal
autoheader
libtoolize -c
automake -a -c
autoconf
./configure
Este script es posible que nos avise de que nos faltan librerías, herramientas, paquetes... instalar lo que os vaya pidiendo y paciencia. Su función es precisamente controlar que teneis todo lo necesario para generar el contenido del paquete. (La petición de "curses header" es para la instalación de la librería de desarrollo ncurses actualmente sudo apt-get instal libncurses5-dev, pero como "todo pasa y todo queda", comprobar que la versión más actualizada para vuestro sistema es la 5)
make
sudo make install
Nota: Una de las utilidades que crosstool-ng necesita y no menciona es svn... con lo que aseguremonos de que está antes de intentar generar nada (sudo apt-get install subversion)
Generación de la toolchain que nos permitirá compilar para la raspberry
Nos posicionamos en el directorio donde queramos crear la toolchain. Por defecto crosstool-ng lo fija a ${HOME}/x-tools/${CT_TARGET}, pero este valor puede cambiarse si se desea durante la configuración.
Ejecutamo ct-ng menuconfig
Paths and misc options:
- Seleccionaremos "Try features marked as EXPERIMENTAL"
- Si no deseamos que la toolchain se genere en el directorio por defecto, esto puede cambiarse en el apartado "prefix directory"
- "Number of parallel jobs" nos permite aprovechar la potencia de una máquina de desarrollo con más de un núcleo, el número a seleccionar puede ajustarse al número de núcleos (algunos manuales hablan de número de núclesos X 1.5 redondeando hacia abajo. He optado por la cifra más conservadora)
Target options:
Nota: El significado de los parámetros que vamos a utilizar puede consultarse en http://es.wikipedia.org/wiki/Raspberry_Pi#Hardware y en http://es.wikipedia.org/wiki/Arquitectura_ARM buscando la raspberrypi entre los chips listados.
- Target architecture: arm (Al seleccionar esta opción ya asume de forma inmediata valores por defecto para endiannes, bitness, juego de instrucciones...)
- Architecture level: armv6zk
- Emit assembly for CPU: arm1176jzf-s
- Tune for CPU: arm1176jzf-s
Y llegamos a la parte de configurar la forma de manejo de la coma flotante, que puede dar problemas. Depende mucho de la distribución para la que queramos compilar, y debe concordar con ella.
Así que mirando en la configuración guardada en https://github.com/raspberrypi/tools/blob/master/configs/bcm2708hardfp-ct-ng.config para el compilador de la raspbian, comprobamos que no han definido una FPU específica, pero sí han definido que el manejo de la coma flotante se haga a través de hardware.
- Floating point: hardware (FPU)
Toolchain options
Puede quedarse tal y como está. Si nos hace ilusión, en Tuple's vendor string podemos poner una cadena que nos ayude a distinguir los ejecutables generados de cualquier otra toolchain que utilicemos
Operating system
- Target OS: Linux
- Linux Kernell: El que utilce nuestra distribución de la raspberry. Si la hemos bajado de http://www.raspberrypi.org/downloads lo más usual es que incluyan la versión del kerrnell en los datos de la distribución. No todas las versiones están disponibles, en caso de que la nuestra no estuviera disponible elegiríamos primero aquella que coincidiera la versión, dentro de aquellas las que coincidiera la revisión. La revisión menor no es muy importante, en caso de duda, elegir un número por debajo (siempre que eso no signifique cambiar a otra con distinta versión o revisión) Es decir, que si la version que aparece listada en mi distribución es la 3.6 y tengo disponibles 3.5, 3.6.11 y 3.7, escogeré la 3.6.11
Binary utilities
No es necesario modificar nada
C Compiler
- Seleccionar C++ entre los "lenguajes adiccionales" (y por supuesto cualquier otro que queramos utilizar)
- Seleccionar "show linaro versions" (aunque esto no es estrictamente necesario, es conveniente. Parte porque Linaro está especializado en desarrollo para ARM, y parte porque muchas de las distribuciones de raspberry lo utilizan. En la duda, de nuevo, consultar la configuración del crosscompilador utilizado en nuestra distribución.)
- Elegir la versión de compilador más avanzada, salvo que tengamos fuertes razones para sospechar que no es estable.
C Library
- Seleccionar la versión de eglibc que coincida con nuestra distribución. Para ello basta ejecutar ldd --version dentro de la rapberry
- Seleccionar "optimize eglibc for size"
Debug Facilities
Aquí depende de lo que cada cual suela usar, yo opto por seleccionar gdb, strace y ltrace
Ahora ejecutamos ct-ng build (y podemos dedicarnos a otra cosa que esto va a tardar lo suyo)
Nota: Al realizar este paso me encontré con un fallo en la creación del debugger gdb, "python is missing or unusable". Afortunadamente tras una breve búsqueda resultó ser un fallo ( ya detectado ) que se soluciona instalando los paquetes develop de phyton. Cometí el error sin embargo de instalar la última versión, que no era la que busca la configuración. Una búsqueda en el log (grep python build.log) mostró que la que andaba buscando era la 2.7.
sudo apt-get install python2.7-dev
y, de nuevo ct-ng build
Y ahora si, la creación se realiza por completo.
Con esto nos habrá generado un directorio arm-<vendor string>-linux-gnueabi, y dentro de el un bin con los compiladores, linkadores, utilidades de debug, etc:
Nota: Vendor string es esa cadena que pusimos en la configuración, dentro de "toolchain options"
En mi caso he elegido un vendor string que me ayude a diferenciar tanto que es una toolchain casera como su función (chus4raspbian)
#include <stdio.h>
int main()
{
printf("Chus se curró una toolchain enterita y solo sacó otra frase tonta. Menuda ñoñería.\n");
return 0;
}
Compilamos:
~/raspberrypi/toolchain/arm-chus4raspbian-linux-gnueabi/bin/arm-chus4raspbian-linux-gnueabi-gcc -o holamundo2 holamundo2.c
Lo copiamos con scp a la raspberry:
scp holamundo2 pi@<dir IP de la rasp>:/home/pi/
Y ejecutamos dentro de la rasp para ver si todo funciona como es debido:
Pues sí. Funciona perfectamente. Para mi sorpresa, porque esperaba que no mostrara bien las eñes y los acentos :) :) :)
sudo apt-get install python2.7-dev
y, de nuevo ct-ng build
Y ahora si, la creación se realiza por completo.
Con esto nos habrá generado un directorio arm-<vendor string>-linux-gnueabi, y dentro de el un bin con los compiladores, linkadores, utilidades de debug, etc:
Nota: Vendor string es esa cadena que pusimos en la configuración, dentro de "toolchain options"
En mi caso he elegido un vendor string que me ayude a diferenciar tanto que es una toolchain casera como su función (chus4raspbian)
Hola de nuevo, raspberry
Ahora solo queda probar que funciona. Como en el post Crosscompilando. Facil y rápido definimos para ello un programa "holamundo2.c"#include <stdio.h>
int main()
{
printf("Chus se curró una toolchain enterita y solo sacó otra frase tonta. Menuda ñoñería.\n");
return 0;
}
Compilamos:
~/raspberrypi/toolchain/arm-chus4raspbian-linux-gnueabi/bin/arm-chus4raspbian-linux-gnueabi-gcc -o holamundo2 holamundo2.c
Lo copiamos con scp a la raspberry:
scp holamundo2 pi@<dir IP de la rasp>:/home/pi/
Y ejecutamos dentro de la rasp para ver si todo funciona como es debido:
Pues sí. Funciona perfectamente. Para mi sorpresa, porque esperaba que no mostrara bien las eñes y los acentos :) :) :)






