As I mentioned in previous posts, I managed to get Mono compiled and running under Debian running side by side with Android. I built Mono "natively" by setting up the Debian environment in the emulator. For the sake of having all the instructions in one place on how to set up a native build environment under Debian, I will be consolidating and tweaking the directions from Saurik's post on how to set up Debian on the G1.

Update 1: If you want an installable Mono APK, which is trimmed down to bare minimum dependencies (3MB) and works on non rooted phones, click here or get it off Market. I have updated the instructions below to reflect the configuration and steps I took to build Mono to create this APK.

Update 0: If you just want a premade SD card image for your phone, skip to the very end of this post about deploying Mono to a real phone and follow the directions from there.

Setting up a Native Build Environment under Debian

If you follow the instructions to build Mono for ARM, you will fail miserably. Doing native builds on a G1 is not an option: the hardware is slow, runs out of memory, and just becomes unstable and unresponsive. Ultimately the watchdog timer kicks in and restarts the phone. However, the emulator does not have this issue. It runs faster than a G1, and you can tweak the qemu options to allocate extra RAM. So, the emulator makes a perfect "native" build environment!

As I mentioned, Mono will run under Debian. The Debian installation will be run off the SD card, contained in an ext2 image file. We will set up the ext2 image in the emulator, build Mono, and then transfer the image to a real phone.

Go to a directory somewhere and create a workspace for the installation:

mkdir monoimage

cd monoimage

Set up the SD card image to be used by the emulator by using the mksdcard command that comes with the Android SDK:

# use whatever size you wish

mksdcard 800MB sdcard.img

Build the Debian image as per the instructions in Saurik's post:

sudo apt-get install debootstrap

# use a size smaller than your SD card, must be less than 4GB as that is the max file size for FAT

Time to start the emulator with SD card image we created. However, before we can can do that, we need to make a quick change. The emulator does not support ext2 out of the box, but that can be fixed by recompiling the kernel. I have a prebuilt emulator kernel available for download. (For further do it yourself instructions on how to compile the Android kernel manually, check out Motz's instructions. After following his instructions, you can use "make menuconfig" to tweak the kernel build options and then use "make" to build it.)

# Let's restart the prompt to get rid of that "I have no name!" problem.

exit

# Ignore any errors again. You should get a "localhost:/#" bash prompt now.

. /sdcard/kit/bash.sh

Building Mono

Whew! You now have a full Debian distribution on the emulator. Now that we're set up, let's get the ARM portion of Mono built. But first, let's grab all the updates, dependencies, and tools we will need to build it.

apt-get update

apt-get install bison libglib2.0-0 libglib2.0-dev bzip2 gcc make

cd ~

# The following URL is the trunk snapshot at the time of writing this entry.

# gmcs IS a managed executable; and obviously quite a complex one at that.

# If it succeeds. Then Mono is working... quite well.

gmcs hello.cs

# Hello World!

mono hello.exe

Before we transfer the Debian image to a real phone, let's shut down gracefully again:

# Exit bash

exit

# Unmount the ext2 image

. /sdcard/kit/umount.sh

# Exit adb shell

exit

Putting Android onto a Real Phone

If you just want a a premade SD card image that contains a working Debian install and Mono runtime, click here. Unzip the sdcard.zip and follow the instructions below to transfer the debian.img (which is contained in the sdcard.img) to your phone.

# It is actually much faster to mount your phone's SD card as a removable disk on your

# computer and copy the kit directory over from the sdcard.img to the real SD card.

# It is also less likely to be corrupted as well. Don't use adb push unless you really want to.

adb push sdcard/kit /sdcard/kit

Now, go to a bash prompt on your phone and you will be able to run Mono!

adb shell

. /sdcard/kit/bash.sh

cd ~

mono hello.exe

What Now?

Well, now Mono is running on Android, side by side with Debian. However, attempting to invoke it from outside of a chroot /bin/bash will result in a "not found" error. This is because Mono is not configured to use Android's linker (/system/bin/linker), and looks for it at "/lib/linux-ld.so.3". You can fix that by doing the unionfs trick that Saurik posted about in his blog.

However, this process still requires the phone to have root, and have a Debian installation. For this to really be viable, Mono would need to be compiled statically, with all its dependencies. And I have no idea how to do that, yet. If someone does, please let me know!

I've tried the -static flag; it doesn't work; didn't look into it further though. It's a bit of a kludge. :)

The cause of the problem is that mono is looking for the linker at /lib/ld-linux.so.3, which does not exist on Android. Android's linker is /system/bin/linker. However, by using the --dynamic-linker option on ld, you can change where an executable looks for the linker.

So, basically by passing "--dynamic-linker ld-linux.so.3" to the linker during make, and make sure that the linker (and all of Mono's dependencies) are in the same directory as mono.

I've tested with a few simple programs to verify it works-- and it does.

Furthermore, this should work for *all* phones, not just jailbroken ones.

Here are the list of dependencies of Mono (each dependency may have further unlisted dependencies).

To elaborate further on why "--dynamic-linker ld-linux.so.3" works (in case it isn't obvious).

Since it is not a full coded path, executables will look for that file in their (current) directory at runtime.

I should probably write this up in a separate post-- I know a lot of other Android developers are also trying to make the standard ARM/Linux build outputs work on Android.

The downside to this is that libc.so.6 is 5 times the size of /system/bin/libc.so. And we'd effectively be loading the same library twice into memory. The optimal solution is to recompile everything to reference Android's libc.so. Or, maybe customize ld-linux.so.3 to special case libc. But that might not work-- I'll take a wild stab and say that Android's libc may just be a subset of ARM/Linux libc due to the disparity in file sizes.

Total disk footprint of Mono and all it's dependencies is 6598288. I'm trying a build with eglib now (and I'm also going to change the path of the linker and see if it works on Android out-of-box). Crossing my fingers...

Is it likely that consumers could benefit of these developments ? I mean could I develop applications for the Android platform that users could run on a G1 for example without having to do anything else then installing my app ?

I followed your instructions trying to run in the Android emulator a .Net 2.0 Winforms application (graphics, audio) created in SharpDevelop on Vista. First I tried using Mono.apk; my app crashed, the error raised was something like "Winforms assembly not found". Then I mounted your sdncard.img image file (the one with debian and mono prebuilt), launched the Android emulator with the mofified ext2 kernel image, then tried to run /sdcard/kit/bash.sh. As you know, files on the sdcard cannot be either run or set as executables. So I opend bash,sh on my Linux box and then executed the commands within in the Android shell. Finally, I copied my .net executable and files from my Linux box to the /home folder in the debian mounted system. Upon issuing mono myapp.net it crashed with an error message pointing to a unimplemented property in Winforms.