Monday, October 14, 2013

Android Programming with Lazarus through Custom Drawn Interface

OK, so you've read that it's possible to write Android applications with Lazarus and Free Pascal. You go straight to the wiki, follow the bunch of steps there and FAIL! And then you start grumbling and doubting whether it's really possible or just a joke.

Listen up, dude. The Android support in FPC is still in development, and a pure arm-android target has just been added a couple of months ago. This target is available for those experienced enough with FPC (bootstrapping the compiler, set options for building, etc.) and not lazy to do the whole setup. Most problems come from those who don't read and do the steps thoroughly, possibly skipping important part. So if you're one of them, either change your behavior or wait until the support is available in the stable release.

I will try to explain step by step setting up FPC trunk with arm-android target support, followed by setting up Lazarus to support building Android application. Note that it's all done on Linux (Kubuntu 13.04) 32-bit, but it should work for any supported host platforms.

First thing first, latest stable FPC


FPC is a bootstrapping compiler, and it's guaranteed that latest stable version will be able to build trunk and next stable version. No guarantee for older version or between revisions of trunk, and things can be broken anytime on trunk. At this time of writing, latest stable FPC is of version 2.6.2. So grab that one if yours is not.

Next, Android NDK


For arm-android target, FPC makes use of external assembler and linker provided by Android NDK. Mine is still version r8e, but looking at the changelog version 9 should work just fine. Extract it anywhere you want, we will refer to this location as {ndk.dir}. To be sure, right under {ndk.dir} there should be README.TXT and RELEASE.TXT.

Let's identify the tools we need:
  • {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-as (assembler)
  • {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ld (linker)
If you want, you can change the part after /toolchains/ in case you want to use androideabi 4.6 or 4.7. Look at the corresponding directory you have in your {ndk.dir}.

Open up your fpc.cfg file, by default it should contain the line:

-XP$FPCTARGET-

This line tells the compiler to prepend any external tools called with $FPCTARGET- (note the dash), so when the compiler wants to call "as", for arm-android target, it will call "arm-android-as" instead. As you can see, the name is then inconsistent with the NDK tools name. The solution is to create symbolic links for the tools with names expected by the compiler. For hosts that don't support symbolic links (e.g. Windows), you can create a small exe wrapper for the tools, or simply rename the tool. Put the symbolic links / wrappers somewhere in PATH (I put it in /usr/bin/).

Ensure you do it correctly by verifying the output of ls -l `which arm-android-<toolname>` (*nix only). It looks like this on my system (real directory replaced with {ndk.dir}):

$ ls -l `which arm-android-as`
lrwxrwxrwx 1 root root 120 Mar  8  2013 /usr/bin/arm-android-as -> {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-as
$ ls -l `which arm-android-ld`

lrwxrwxrwx 1 root root 120 Mar  8  2013 /usr/bin/arm-android-ld -> {ndk.dir}/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ld

Try executing arm-android-as and arm-android-ld in terminal or command prompt to ensure it works.

Next, FPC trunk


Get FPC trunk either from svn (I won't teach how to use svn, go find tutorial somewhere) or Free Pascal's FTP. In case of svn, here's the address: http://svn.freepascal.org/svn/fpc/trunk

Build FPC for arm-android target


Using your terminal, go to FPC trunk directory and execute the following:

make crossall OS_TARGET=android CPU_TARGET=arm CROSSOPT='-Cp<ARM Arch> -Cf<ARM VFP>'

<ARM Arch> defines the ARM architecture you want to compile for, my device is ARMv6, so I use -CpARMv6.
<ARM VFP> defines the Vector Floating Point unit you want to use for floating point calculation, for at least ARMv6, VFPv2 and VFPv3 are available. The default is to use soft-float, which is very slow as the calculation is performed by software. Since I seldom use floating point, soft-float is fine for me, so I don't pass any -Cf option.

If everything goes well, it's time to install. Execute the following (still in the same FPC trunk folder):

make crossinstall OS_TARGET=android CPU_TARGET=arm INSTALL_PREFIX=<directory of your choice>

Feel free to choose any directory you want, but ensure it fulfills the standard requirement (no space in the file path). I suggest installing to the same host FPC directory so you can easily share fpc.cfg. FPC directory structure is made such that it's possible to install cross compiler (and the respective units) in the same tree as the host compiler. The fpc driver can then be used to query which ppc[ross]XXX to call.

If everything goes well, test the compiler. Execute the following:

fpc -Parm -Tandroid

It should output something like:

Free Pascal Compiler version 2.7.1 [2013/09/21] for arm
Copyright (c) 1993-2013 by Florian Klaempfl and others
Fatal: No source file name in command line
Fatal: Compilation aborted

Error: /usr/bin/ppcrossarm returned an error exitcode

Next, Android SDK


Grab Android SDK if you haven't, r22 should be fine. We just need the SDK tools, so no need to waste time and bandwidth downloading the ADT bundle. I will refer to the SDK installation directory as {sdk.dir}. To be sure, right under {ndk.dir} there should be SDK README.TXT.

Test AndroidLCL example, yay!


Go to your Lazarus installation directory (I will refer it as {lazarus.dir} from now on) and open examples/androidlcl/androidlcltest.lpi. Now open Project->Project Options, ensure in Target Platform OS is set to android and CPU is set to arm (or just pick the respective build mode). If upon FPC trunk building you use -Cf option, specify the same option in Other. You might need to also set it in Tools->Configure Build Lazarus dialog. Now press the Run->Build menu. If you get:

Trying to use a unit which was compiled with a different FPU mode

Then you don't put the -Cf option correctly. Remember you will need to put it for both your project (through Project Options dialog) and LCL (and its dependencies, through Configure Build Lazarus).

If everything goes well, you will get android/libs/armeabi/liblclapp.so in the project folder.

Get Ant


Android SDK uses ant build tool for building apk, so you'll need to install it as well.

Build the APK


Go to android folder under androidlcl project folder, and open the build.xml. Inside, you will see 2 loadproperties and 1 property tags. These points to files you will need to edit to match your SDK installation. Mine is below:

<loadproperties srcFile="local.properties" />
<property file="ant.properties" />
<loadproperties srcFile="default.properties" />

local.properties contains the sdk.dir which you should fill with {sdk.dir} (actual value where you install it, of course).
default.properties contains the target android API level. The complete list can be seen here. Note that you have to install the respective SDK platform through Android SDK manager.
ant.properties contains key.store and key.alias which is required for release version of your apk. For debug version, it's not required and the apk builder utility will assign a debug key on its own.

If all set, execute:

ant debug

in android folder. The resulting .apk will be in android/bin folder named LCLExample-debug.apk. Install that and enjoy.

From this point forward, you can make use of androidlcl structure as a template. General Java package structure and Android build system knowledge will be required to change the package name.

l
It 

10 comments:

  1. A little helpful note for the Windows people out there: Only the bfd version of ld works, the others are unable to parse the link script properly. So copy arm-linux-androideabi-as.exe to arm-android-as.exe and arm-linux-androideabi-ld.bfd.exe to arm-android-ld.exe and you should be all good.

    ReplyDelete
  2. Keren mas! I see you're a die-hard pascal fan :)

    Nice to meet you, i visited your profile in stackoverflow. Ini profil saya:
    http://stackoverflow.com/users/2106009/aikid

    ReplyDelete
  3. I am a hobbyist programmer and used Pascal for more than 20 years. Pro? nah, but i know my way around it.

    I simply followed your guide and found out"hey, this breaks" and then went to ask the nice people on freenode for a hint, so i thought i would share it here,

    And yeah, things are so much easier on linux, been using it since kernel 0.13 :)

    Have a good day, however you say that in your language! :)

    ReplyDelete
  4. Hi. I came across your post today. Lazarus has always been fascinating to me. The question is, once we get an Android application running, is it practical to release a real application with it? For most languages other than Java, the answer is "No, because you will need to install a 1.7 terabyte library along with your application." Your comment on whether it will ever be practical to write an Android application in Pascal would be very useful.

    ReplyDelete
  5. I suppose you tried Embarcadero's Android version of Delphi? :) I was so amazed at how you could make "Hello World" take up 29 megabytes, it's ridiculous!

    FreePascal for Android is still very recent and as such not optimized, but you don't get that much overhead really. And unlike Delphi, its quite snappy at the response time on your devices - even on my dirt old Archos tablets, my apps run pretty okay. So yeah, you can do quite a lot in a couple of megs without having to link unnecessary shared objects.

    Can only speak from what i have tried and suited my needs of course, but so far, the workarounds have been very minor. There's even a version of FreePascal that runs on Android, but i haven't toyed with it much.

    ReplyDelete
  6. @Bo, Disable debugging in Lazarus to get your executable file smaller.

    ReplyDelete
  7. @Caleb, i know that, i was talking about Delphi for Android, which makes ridiculously large executables, even with no debug and all optimizations.

    ReplyDelete
  8. If you are searching for cost effective as well as solid Mobile Application Development Services and Web Development in India provider then without thinking much you can choose to hire the services offered by Acetech. We are one of the leading companies offering affordable, timely and quality mobile apps services.

    ReplyDelete
  9. Just a general note...re-evaluate your opening statement ;). Pascal has Never been a "toy" language... It was initially in competition with C++, making it one of the lowest level object orientated languages around.

    Microsoft are the culprits when it comes to toy languages...the older version of VB being the prime example. Microsoft has always pushed languages to be accessible to people without formal programming knowledge leading to poorly written, sub-quality programmes...

    Lower level languages will never and can never die...

    ReplyDelete
  10. Thank you man, your article saved my life, or at least my keyboard. I was almost purging my rage on it.

    ReplyDelete