Ricerca tra la vecchia roba

Buildare eseguibili per android

Posted: Ottobre 9th, 2011 | Author: | Filed under: Guide | Tags: , , , , , , , , | Commenti disabilitati su Buildare eseguibili per android

Un mio progetto segreto (?) durante l’hackit è stato capire come eseguire il cross-compiling su android;  come argomento pare essere già stato affrontato da altri ma senza che nessuno abbia prodotto un tutorial completo. Dopo una prima occhiata sull’argomento parrebbero esserci almeno N metodologie per cross-compilare su android (per chi non lo sapesse apparecchi come i nostri smartphone hanno un processore ARM).

Quello che segue può sembrare un po’ roba sparsa ed in tal caso c’avete ragione.

LIBC

Prima di tutto bisogna sapere che la libreria standard utilizzata per i processi che vengono eseguiti su questo sistema non è la glibc ma è chiamata bionic; questa è stata pensata per girare su sistemi embedded e quindi non ha tutte le potenzialità/funzionalità delle più note omologhe librerie , in particolare c’è da tener presente che non è supportata la gestione dei locale(7) direttamente da C ma bisogna passare da Java (per esempio wget non compila proprio per questa problematica e anche lua ha lo stesso problema). Inoltre ha una gestione propria dei thread (quindi niente original linux threads/NPTL ).

LINKER

Il linker è il programma che si deve preoccupare in un sistema operativo di caricare le librerie necessarie ad un adeguato programma; in linux è chiamato linux-vdso.so.1 mentre in android si è scelto di usare il programma il cui path è /system/bin/linker. Al contrario dei linker UNIX che rispettano la variabile d’ambiente LD_LIBRARY_PATH esso cerca solamente le librerie in /system/lib/ e /lib/ e questo è un casino. Qualche info

  • http://www.koushikdutta.com/2009/05/androids-linker-makes-baby-jesus-cry.html
  • http://groups.google.com/group/android-developers/browse_thread/thread/a76d1822ed0021ac
  • http://android.git.kernel.org/?p=platform/bionic.git;a=blob;f=linker/linker.c;h=00f36c07a663c25219d8d963c2b753914383bc11;hb=HEAD

Un modo per evitare i casini è buildare gli eseguibili staticamente.

SISTEMA DI BUILD DI ANDROID

Il sistema android utilizza una versione moddata di Makefile che si preoccupano di ricostruire le dipendenze, buildare librerie ed eseguibili e copiarle nella immagine disco da flashare nell’apparecchio.

L”unico problema è che non si possono utilizzare gli autotools o cmake ma si deve scrivere un makefile apposito, chiamato Android.mk, tramite cui effettuare la compilazione. Si capisce subito che se abbiamo già un progetto avviato e di una certa complessità è molto difficile scrivere uno di questi file senza problemi (e non dimentichiamoci del suo mantenimento successivo).

Siccome per adesso sono interessato a compilare programmi che già utilizzano gli autotools mostrerò come compilare staticamente/dinamicamente passando parametri opportuni a configure.

Per chi è interessato a compilare roba per android utilizzando CMake è interessante utilizzare le istruzioni per il cross compiling di openCV.

COMPILATORE

Per compilare ovviamente serve un compilatore e tutta la toolchain ed una prima opzione è la toolchain arm sourcery con la quale è possibile compilare staticamente; opzioni simili sono la toolchain della SDK ed NDK scaricabili dal sito di android. Il problema con queste due soluzioni è il dover elencare a manina tutti i flags necessari per linkare correttamente il programma al sistema di android che non è proprio un cazzo facile per le questioni espresse più sopra.

Proprio per questo una valida alternativa è il progetto droid-wrapper, esso si propone di creare uno script che configuri gcc ed ld per compilare programmi utilizzando i normali autotools. Ci si deve solo premurare di aver prima compilato i sorgenti di android.

Una volta scaricato il progetto con git è possibile facilitarne l’uso creando uno script che imposti le variabili d’ambiente in maniera corretta (la directory in cui è stato scaricato nel nostro caso è /opt/droid-wrapper/ con i sorgenti di android in /opt/android-source/)

$ cat .bash_droid
export DROID_ROOT=/opt/android-source/
export DROID_TARGET=generic
export PATH=/opt/droid-wrapper/bin/:$PATH

echo "usa CC=droid-gcc LD=droid-ld ./configure --host=arm-linux-eabi"

Una cosa da tener presente quando si effettua il cross compiling (cioè il compilare del codice per piattaforma diversa rispetto a quella in cui gira il compilatore) è la naming convention usata dai compilatori: un compilatore di questo tipo ha un prefisso costruito usando il seguente schema

arch-vendor-(os-)abi

Per esempio la toolchain della sourcery citata poco più sopra ha un prefisso dato da arm-none-linux-gnueabi. Tenete presente che la toolchain che vorrete usare deve essere nel vostro PATH altrimenti nulla compilerà.

Vediamo adesso come compilare alcuni tools utili per i very hackerz.

BUSYBOX

Busybox è un singolo programma che racchiude internamente praticamente tutte le utility UNIX ri-implementandole e permettendo così di avere un sistema funzionante con un singolo eseguibile anche in sistemi embedded. Nel caso di android questo risulta molto utile proprio per evitare di dover compilare tutti gli eseguibili necessari uno per uno.

Per compilarlo staticamente usando la toolchain prescelta basta eseguire

$ make menuconfig

e nel menù che compare,  inserire in

Busybox Settings > Build options > Cross Compiler prefix

l’identificativo della toolchain prescelta! Un make builderà per voi tutte le utility in un singolo eseguibile chiamato busybox.

BASH

Fila tutto liscio usando

$ ./configure --host=arm-none-linux-gnueabi --enable-static-link --without-bash-malloc

VIM

Un primo esempio di programma che può tornare utile a voi hackerz è il mitico editor: a causa della sua complessità non è possibile compilarlo dinamicamente; usiamo la toolchain sourcery

export PATH=/opt/arm-sourcery-g++-lite/bin:$PATH

Prima di tutto si necessita delle librerie ncurses che possono essere compilate con un semplice

$ ./configure --host=arm-none-linux-gnueabi && make

Chiamando NCURSES_PATH la variabile dove si imposta il path per le librerie appena sopra compilate

vim_cv_memmove_handles_overlap=no \
 vim_cv_toupper_broken=set \
 vim_cv_memcpy_handles_overlap=no \
 vim_cv_bcopy_handles_overlap=no \
 vim_cv_stat_ignores_slash=no \
 vim_cv_getcwd_broken=no \
 vim_cv_tty_group=world \
 vim_cv_terminfo=yes \
 LDFLAGS="-L$NCURSES_PATH/lib/ -static" \
 CFLAGS=-I$NCURSES_PATH/include/ ./configure --host=arm-none-linux-gnueabi --with-tlib=ncurses

Potrebbe uscire un errore al check per int32: per risolverlo editate src/auto/configure eliminando il controllo che ha restituito l’errore. Ma non è finita qui: dando make vi uscirà un errore

auto/osdef.h:117: error: previous declaration of 'tgoto' was here

e per risolverlo dovete andare ad eliminare le funzioni di cui si lamenta il compilatore definite in src/auto/osdef.h; finito ridate make. Finito di compilare potete caricare nel device il programma

adb push src/vim /data/local/tmp/

e lanciarlo da una shell con

TERM=xterm-color vim

Ovviamente così molte cose non funzioneranno alla perfezione, per esempio l’help.

Tutto questo è una rielaborazione di questo post http://credentiality2.blogspot.com/2010/08/native-vim-for-android.html.

EMULATORE

Si possono installare i programmi anche sull’emulatore tenendo conto che

  1. se si vuole installare roba nella cartella di sistema, bisogna rimontare la partizione /system in read-write mode (mount -o rw,remount -t yaffs2 /dev/block/mtdblock0 /system)
  2. è probabile che la partizione /system non sia grande abbastanza quindi si deve far partire l’emulatore con una size adeguata (emulator -avd test2.3.3 -partition-size 1024)

ROBA IN GENERALE

Per qualche info in più leggere