WORK IN PROGRESS
This note is not about installing or using Eclipse, so you should be familiar with it a bit. Also this note is not about installing Android NDK and Android SDK, but you can check useful links :)
Requirements
Before you will be able to compile anything for Android you should get next:
For this note I will use ArchLinux(but you able to choose any other GNU/Linux distributive). For users who use Windows I will describe everything using Windows XP. Also there is possibility to use MacOS X for developing for Android, but I will omit this(you want note for MacOS X a lot? contact me).
Note: You can download precompiled version of FreePascal for Android here, if you don't want to understand how everything is works.
So, you installed all required above and now you need to compile cross-compiler of FreePascal for Android. Here is a script for this:
export PPCBIN=fpc # but if you use different versions of FreePascal, it will be better to write here full path, e.g. /usr/lib/fpc/2.6.0/ppcx64 export ANDROID_BIN=$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/arm-linux-androideabi/bin rm -Rf /tmp/fixes_2_6 if [ -d ./fixes_2_6 ]; then svn update ./fixes_2_6 -r 20768 else svn co http://svn.freepascal.org/svn/fpc/branches/fixes_2_6 ./fixes_2_6 -r 20768 fi svn export ./fixes_2_6 /tmp/fixes_2_6 cp dumbfix.patch /tmp/fixes_2_6 cp android_pthreads.patch /tmp/fixes_2_6 cp android_dl.patch /tmp/fixes_2_6 cd /tmp/fixes_2_6 patch -p0 < dumbfix.patch patch -p0 < android_pthreads.patch patch -p0 < android_dl.patch make FPC=$PPCBIN build OS_TARGET=linux CPU_TARGET=arm OPT="-dFPC_ARMEL" CROSSOPT="-dANDROID -CpARMv6 -CfVFPv2" CROSSBINDIR=$ANDROID_BIN sudo make FPC=`pwd`/compiler/ppcrossarm PREFIX=/opt/fpc crossinstall OS_TARGET=linux CPU_TARGET=arm OPT="-dFPC_ARMEL" CROSSOPT="-dANDROID -CpARMv6 -CfVFPv2" CROSSBINDIR=$ANDROID_BIN rm -Rf /tmp/fixes_2_6Download it and three patches from here and put these files into the same directory and open terminal in it. Before executing the script via command “sh ./build_fpc_2_6_arm.sh” you will be needed to edit this script a bit. First of all replace $ANDROID_NDK with place where you installed Android NDK(but if you use ArchLinux there is no need to do so because this is an environment variable which should be available after installation of this package). Another moment - place where to install cross-compiler. Because I don't like an idea to install experimental version of cross-compiler into my /usr I used this path - /opt/fpc(see option PREFIX). After modifying the script you can run it. It will put everything needed for compilation into /tmp directory and before installation will ask for a password. At the end don't forget to do this:
sudo ln -s /opt/fpc/lib/fpc/2.6.1 /usr/lib/fpc/2.6.1 # /usr/lib/fpc/ is a default place of installed FreePascal. sudo ln -s /opt/fpc/lib/fpc/2.6.1/ppcrossarm /usr/bin/ppcarmThese commands will make possible to use cross-compiler without changing the fpc.cfg.
For bat file below you will be needed to install svn client, but not the GUI one, like TortoiseSVN, you need a console version of svn client. You can choose such option during installation of TortoiseSVN, or install Slik Subversion.
So, you installed all required above and now you need to compile cross-compiler of FreePascal for Android. Here is a bat file for this:
Download it and three patches from here and put these files into the same directory. Before executing the bat file you will be needed to edit this file(standard notepad is a bad idea, so use something else or just copy and paste content of this file from your browser). First of all set correct path to installed Android NDK for ANDROID_NDK variable. Another moment - directories to FreePascal. FPC_PATH - where to find fpc.exe, FPC_INSTALL_PATH - where to install cross-compiler. After modifying the bat file you can run it.
Compatibility
ZenGL uses floats for rendering and so on, so using hard float instead of soft float is very important. In build scripts of FreePascal you can find such options like -CpARMv6 -CfVFPv2, and if you want to support very old devices and get poor performance you can replace these options to -CpARMv5 -CfSOFT.
WARNING! Android Emulator doesn't support ARMv6, so don't even try to test ZenGL demos and so on with emulator(Note: seems using emulator with Android 4.x provide possibility to use even ARMv7 binaries).
FreePascal officialy doesn't support Android, so there are some problems. Here is a list of known issues:
Patches
dumbfix.patch is needed because of this bug, which prevents possibility to use SysUtils, Classes and Math units.
dumbfix.patch --- rtl/linux/system.pp +++ rtl/linux/system.pp @@ -332,6 +332,12 @@ var initialstkptr : Pointer;external name '__stkptr'; begin + {this is a stupid fix since these are not set correctly under android, + and trying to access argv or envp will make the library crap out} + argc := 0; argv := nil; envp := nil; + {$if defined(i386) and not defined(FPC_USE_LIBC)} InitSyscallIntf; {$endif}android_pthreads.patch is needed for using threads, which are don't work on Android with current code of FreePascal.
--- rtl/linux/pthread.inc +++ rtl/linux/pthread.inc @@ -126,8 +126,10 @@ function pthread_attr_getschedparam(__attr:ppthread_attr_t; __param:psched_param):longint;cdecl;external; function pthread_attr_setschedpolicy(__attr:ppthread_attr_t; __policy:longint):longint;cdecl;external; function pthread_attr_getschedpolicy(__attr:ppthread_attr_t; __policy:plongint):longint;cdecl;external; function pthread_attr_setinheritsched(__attr:ppthread_attr_t; __inherit:longint):longint;cdecl;external; function pthread_attr_getinheritsched(__attr:ppthread_attr_t; __inherit:plongint):longint;cdecl;external; function pthread_attr_setstacksize(p: ppthread_attr_t;s:size_t):cint;cdecl;external; function pthread_attr_getstacksize(p: ppthread_attr_t;s:psize_t):cint;cdecl;external; function pthread_attr_setscope(__attr:ppthread_attr_t; __scope:longint):longint;cdecl;external; @@ -197,8 +199,10 @@ pthread_attr_getschedparam : Function(__attr:ppthread_attr_t; __param:psched_param):longint;cdecl; pthread_attr_setschedpolicy : Function(__attr:ppthread_attr_t; __policy:longint):longint;cdecl; pthread_attr_getschedpolicy : Function(__attr:ppthread_attr_t; __policy:plongint):longint;cdecl; pthread_attr_setinheritsched : Function(__attr:ppthread_attr_t; __inherit:longint):longint;cdecl; pthread_attr_getinheritsched : Function(__attr:ppthread_attr_t; __inherit:plongint):longint;cdecl; pthread_attr_setscope : Function(__attr:ppthread_attr_t; __scope:longint):longint;cdecl; pthread_attr_getscope : Function(__attr:ppthread_attr_t; __scope:plongint):longint;cdecl; pthread_setschedparam : Function(__target_thread:pthread_t; __policy:longint; __param:psched_param):longint;cdecl; @@ -211,32 +215,40 @@ pthread_mutex_unlock : Function(__mutex:ppthread_mutex_t):longint;cdecl; pthread_mutexattr_init : Function(__attr:ppthread_mutexattr_t):longint;cdecl; pthread_mutexattr_destroy : Function(__attr:ppthread_mutexattr_t):longint;cdecl; pthread_mutexattr_setkind_np : Function(__attr:ppthread_mutexattr_t; __kind:longint):longint;cdecl; pthread_mutexattr_getkind_np : Function(__attr:ppthread_mutexattr_t; __kind:plongint):longint;cdecl; pthread_cond_init : Function(__cond:ppthread_cond_t; __cond_attr:ppthread_condattr_t):longint;cdecl; pthread_cond_destroy : Function(__cond:ppthread_cond_t):longint;cdecl; pthread_cond_signal : Function(__cond:ppthread_cond_t):longint;cdecl; pthread_cond_broadcast : Function(__cond:ppthread_cond_t):longint;cdecl; pthread_cond_wait : Function(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t):longint;cdecl; pthread_cond_timedwait : Function(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):longint;cdecl; pthread_condattr_init : Function(__attr:ppthread_condattr_t):longint;cdecl; pthread_condattr_destroy : Function(__attr:ppthread_condattr_t):longint;cdecl; pthread_key_create : Function(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl; pthread_key_delete : Function(__key:pthread_key_t):longint;cdecl; pthread_setspecific : Function(__key:pthread_key_t; __pointer:pointer):longint;cdecl; pthread_getspecific : Function(__key:pthread_key_t):pointer;cdecl; { pthread_once : Function(__once_control:ppthread_once_t; __init_routine:tprocedure ):longint;cdecl;} pthread_setcancelstate : Function(__state:longint; __oldstate:plongint):longint;cdecl; pthread_setcanceltype : Function(__type:longint; __oldtype:plongint):longint;cdecl; pthread_cancel : Function(__thread:pthread_t):longint;cdecl; pthread_testcancel : Procedure ;cdecl; { _pthread_cleanup_push : procedure (__buffer:p_pthread_cleanup_buffer;__routine:t_pthread_cleanup_push_routine; __arg:pointer);cdecl;} { _pthread_cleanup_push_defer : procedure (__buffer:p_pthread_cleanup_buffer;__routine:t_pthread_cleanup_push_defer_routine; __arg:pointer);cdecl;} { pthread_sigmask : Function(__how:longint; __newmask:plibc_sigset; __oldmask:plibc_sigset):longint;cdecl;} pthread_kill : Function(__thread:pthread_t; __signo:longint):longint;cdecl; { sigwait : Function(__set:plibc_sigset; __sig:plongint):longint;cdecl;} pthread_atfork : Function(__prepare:tprocedure ; __parent:tprocedure ; __child:tprocedure ):longint;cdecl; pthread_kill_other_threads_np : procedure;cdecl; pthread_sigmask: Function(how: cint; nset: plibc_sigset; oset: plibc_sigset): cint;cdecl; sem_init : function (__sem:Psem_t; __pshared:longint; __value:dword):longint;cdecl; @@ -258,7 +270,11 @@ Function LoadPthreads : Boolean; begin PThreadDLL:=DlOpen('libpthread.so.0',RTLD_LAZY); + PThreadDLL := dlopen( 'libc.so', RTLD_LAZY ); Result:=PThreadDLL<>Nil; If Not Result then exit; @@ -276,8 +292,10 @@ Pointer(pthread_attr_getschedparam) := dlsym(PthreadDLL,'pthread_attr_getschedparam'); Pointer(pthread_attr_setschedpolicy) := dlsym(PthreadDLL,'pthread_attr_setschedpolicy'); Pointer(pthread_attr_getschedpolicy) := dlsym(PthreadDLL,'pthread_attr_getschedpolicy'); Pointer(pthread_attr_setinheritsched) := dlsym(PthreadDLL,'pthread_attr_setinheritsched'); Pointer(pthread_attr_getinheritsched) := dlsym(PthreadDLL,'pthread_attr_getinheritsched'); Pointer(pthread_attr_setscope) := dlsym(PthreadDLL,'pthread_attr_setscope'); Pointer(pthread_attr_getscope) := dlsym(PthreadDLL,'pthread_attr_getscope'); Pointer(pthread_attr_setstacksize) := dlsym(PthreadDLL,'pthread_attr_setstacksize'); @@ -290,31 +308,39 @@ Pointer(pthread_mutex_unlock) := dlsym(PthreadDLL,'pthread_mutex_unlock'); Pointer(pthread_mutexattr_init) := dlsym(PthreadDLL,'pthread_mutexattr_init'); Pointer(pthread_mutexattr_destroy) := dlsym(PthreadDLL,'pthread_mutexattr_destroy'); Pointer(pthread_mutexattr_setkind_np) := dlsym(PthreadDLL,'pthread_mutexattr_setkind_np'); Pointer(pthread_mutexattr_getkind_np) := dlsym(PthreadDLL,'pthread_mutexattr_getkind_np'); Pointer(pthread_cond_init) := dlsym(PthreadDLL,'pthread_cond_init'); Pointer(pthread_cond_destroy) := dlsym(PthreadDLL,'pthread_cond_destroy'); Pointer(pthread_cond_signal) := dlsym(PthreadDLL,'pthread_cond_signal'); Pointer(pthread_cond_broadcast) := dlsym(PthreadDLL,'pthread_cond_broadcast'); Pointer(pthread_cond_wait) := dlsym(PthreadDLL,'pthread_cond_wait'); Pointer(pthread_cond_timedwait) := dlsym(PthreadDLL,'pthread_cond_timedwait'); Pointer(pthread_condattr_init) := dlsym(PthreadDLL,'pthread_condattr_init'); Pointer(pthread_condattr_destroy) := dlsym(PthreadDLL,'pthread_condattr_destroy'); Pointer(pthread_key_create) := dlsym(PthreadDLL,'pthread_key_create'); Pointer(pthread_key_delete) := dlsym(PthreadDLL,'pthread_key_delete'); Pointer(pthread_setspecific) := dlsym(PthreadDLL,'pthread_setspecific'); Pointer(pthread_getspecific) := dlsym(PthreadDLL,'pthread_getspecific'); { Pointer(pthread_once) := dlsym(PthreadDLL,'pthread_once');} Pointer(pthread_setcancelstate) := dlsym(PthreadDLL,'pthread_setcancelstate'); Pointer(pthread_setcanceltype) := dlsym(PthreadDLL,'pthread_setcanceltype'); Pointer(pthread_cancel) := dlsym(PthreadDLL,'pthread_cancel'); Pointer(pthread_testcancel) := dlsym(PthreadDLL,'pthread_testcancel'); { Pointer(_pthread_cleanup_push) := dlsym(PthreadDLL,'_pthread_cleanup_push');} { Pointer(_pthread_cleanup_push_defer) := dlsym(PthreadDLL,'_pthread_cleanup_push_defer');} { Pointer(pthread_sigmask) := dlsym(PthreadDLL,'pthread_sigmask');} Pointer(pthread_kill) := dlsym(PthreadDLL,'pthread_kill'); Pointer(pthread_atfork):= dlsym(PthreadDLL,'pthread_atfork'); Pointer(pthread_kill_other_threads_np) := dlsym(PthreadDLL,'pthread_kill_other_threads_np'); Pointer(pthread_sigmask) := dlsym(PthreadDLL,'pthread_sigmask'); Pointer(sem_init ) := dlsym(PthreadDLL,'sem_init'); Pointer(sem_destroy ) := dlsym(PthreadDLL,'sem_destroy'); =================================================================== --- rtl/unix/initc.pp +++ rtl/unix/initc.pp @@ -52,7 +52,7 @@ {$ifdef Linux} -function geterrnolocation: pcint; cdecl;external clib name '__errno_location'; +function geterrnolocation: pcint; cdecl;external clib name {$IFNDEF ANDROID}'__errno_location'{$ELSE}'__errno'{$ENDIF}; {$endif} {$ifdef FreeBSD} // tested on x86 =================================================================== --- rtl/unix/cthreads.pp +++ rtl/unix/cthreads.pp @@ -21,8 +21,11 @@ b) still enabling dynamically checking whether or not certain functions are available (could also be implemented via weak linking) } {$linklib pthread} {$define dynpthreads} // Useless on BSD, since they are in libc + // Hangs up on Android {$endif} @@ -53,7 +56,7 @@ {$ifndef dynpthreads} // If you have problems compiling this on FreeBSD 5.x {$linklib c} // try adding -Xf - {$if not defined(Darwin) and not defined(iphonesim)} + {$if not defined(Darwin) and not defined(iphonesim) and not defined(ANDROID)} {$ifndef haiku} {$linklib pthread} {$endif haiku} @@ -332,13 +335,13 @@ writeln('Starting new thread'); {$endif DEBUG_MT} pthread_attr_init(@thread_attr); + {$if not defined(HAIKU) and not defined(ANDROID)} {$ifdef solaris} pthread_attr_setinheritsched(@thread_attr, PTHREAD_INHERIT_SCHED); {$else not solaris} pthread_attr_setinheritsched(@thread_attr, PTHREAD_EXPLICIT_SCHED); {$endif not solaris} // will fail under linux -- apparently unimplemented pthread_attr_setscope(@thread_attr, PTHREAD_SCOPE_PROCESS); @@ -409,7 +412,11 @@ function CKillThread (threadHandle : TThreadID) : dword; begin pthread_detach(pthread_t(threadHandle)); CKillThread := pthread_cancel(pthread_t(threadHandle)); + pthread_kill(pthread_t(threadHandle),SIGKILL); end; function CCloseThread (threadHandle : TThreadID) : dword; @@ -507,7 +514,7 @@ {***************************************************************************** Semaphore routines *****************************************************************************} - + procedure cSemaphoreWait(const FSem: Pointer); var res: cint; android_dl.patch --- rtl/unix/dl.pp +++ rtl/unix/dl.pp @@ -27,13 +27,19 @@ {$endif} {$endif} {$if defined(linux) or defined(freebsd) or defined(openbsd)} {$define ELF} // ELF symbol versioning. {$endif} {$if defined(linux) and defined(cpuarm)} { arm-linux seems to require this } {$endif} RTLD_LAZY = $001; @@ -68,38 +74,42 @@ { overloaded for compatibility with hmodule } function dlsym(Lib : PtrInt; Name : Pchar) : Pointer; cdecl; external Libdl; function dlclose(Lib : PtrInt) : Longint; cdecl; external libdl; function dladdr(Lib: pointer; info: Pdl_info): Longint; cdecl; external; implementation function PosLastSlash(const s : string) : longint; var i : longint; - begin + begin PosLastSlash:=0; for i:=1 to length(s) do if s[i]='/' then PosLastSlash:=i; end; - - + + function SimpleExtractFilename(const s : string) : string; begin SimpleExtractFilename:=Copy(s,PosLastSlash(s)+1,Length(s)-PosLastSlash(s)); end; - + procedure UnixGetModuleByAddr(addr: pointer; var baseaddr: pointer; var filename: openstring); var dlinfo: dl_info; begin baseaddr:=nil; FillChar(dlinfo, sizeof(dlinfo), 0); dladdr(addr, @dlinfo); baseaddr:=dlinfo.dli_fbase; filename:=String(dlinfo.dli_fname); if SimpleExtractFilename(filename)=SimpleExtractFilename(ParamStr(0)) then baseaddr:=nil; end; begin compiler version: 2.6.1 svn r20768
compilation options: -CpARMv6 -CfVFPv2
compiled for: GNU/Linux i386/x86_64, Windows i386/x86_64
Download and unpack into your directory with installed FreePascal(e.g. /usr/lib/fpc/2.6.0 or C:\lazarus\fpc\2.6.0). In case with GNU/Linux you should also take binary ppcrossarm from bin/i386-linux or bin/x86_64-linux(depends on your architecture) and copy it manually into /usr/lib/fpc/2.6.0 and create symlink to it into /usr/bin:
sudo ln -sf /usr/lib/fpc/2.6.0/ppcrossarm /usr/bin/ppcarmNumbers 2.6.0 can be different, it depends on version of your FreePascal :)
Useful links
引文来源 compilation:android [ZenGL]