The following does not describe general distributable applications.
It also assumes you know a little bit about Android, compilers, and Linux.
The need for this arose during development, and the technique described
may be suitable for enhancements and additions to the default file system
of an Android-based device.
Basically, Android is a virtual machine environment bolted on top of a linux kernel. You can communicate with that environment through the kernel, but certainly also run stand-alone applications which may have nothing to do with the Android environment. Some examples are hardware tests, communication protocols, or external C++ applications and frameworks which may require exceptions or RTTI.
Here is an outline of the steps for this proof-of-concept exercise:
Next, we want a good target compiler; CodeSourcery maintains free versions
(command-line only, no Eclipse IDE) of their tool chains for ARM. This distro
contains the runtime libraries already built and ready to go, compatible with
the Linux kernel used in Android.
I added this tools path to end of my '.bashrc' file, as:
# add path for CodeSourcery G++ Lite PATH=/opt/CodeSourcery/Sourcery_G++_Lite/bin:$PATH export PATHNow, verify we can execute the compiler, and also check the sysroot for our target ARM core.
[~/]$ arm-none-linux-gnueabi-g++ -march=armv4t -print-sysroot /opt/CodeSourcery/Sourcery_G++_Lite/bin/../arm-none-linux-gnueabi/libc/armv4tNow, assuming you're set up in a similar way, on to the exercise:
#!/bin/bash # # bundle-armv4t.sh # # get the compiler sysroot path for our configuration (armv4t) # e.g. /opt/CodeSourcery/Sourcery_G++_Lite/arm-none-linux-gnueabi/libc/armv4t # THE_SYSROOT=`arm-none-linux-gnueabi-g++ -march=armv4t -print-sysroot` export THE_SYSROOT mkdir ~/temp mkdir ~/temp/armv4t cd ~/temp/armv4t mkdir lib mkdir usr mkdir usr/lib mkdir usr/bin mkdir sbin # copy all required files from the sysroot for our selected target # lib -- all .so and symlinks (use cp -P) # usr/lib -- all .so and symlinks (use cp -P) # usr/bin # sbin cp -P $THE_SYSROOT/lib/*.so* ./lib/. cp -P $THE_SYSROOT/usr/lib/*.so* ./usr/lib/. cp $THE_SYSROOT/usr/bin/* ./usr/bin/. cp $THE_SYSROOT/sbin/* ./sbin/. cd .. mv armv4t sysroot tar -cf sysroot.tar sysrootNow we have a tarball with all symlinks at ~/temp/sysroot.tar (and we can verify).
tar -tf ~/temp/sysroot.tar
Here we will also need tar on the target. I found this available as a statically-linked (less than 1MByte) Android native binary, at http://groomws.info/index.php?title=AndroidNativeBinaries. Locate and download the "Android stripped binary" for tar. (I saved mine as 'android-tar', in the ~/Downloads folder.)
In a separate terminal window, invoke the emulator with the '-shell' option.
(Remember, I'm using a virtual device.)
[~/android-sdk-linux_x86/tools]$ ./emulator -shell -avd Default_AVD #Notice the # prompt is from the Android-based target. (Try 'ls' command.)
Now, from our main terminal window, check for our virtual device. This will also automatically start the server if it's not already running.
[~/android-sdk-linux_x86/platform-tools]$ ./adb devices List of devices attached emulator-5554
Now we transfer the files.
[~/android-sdk-linux_x86/platform-tools]$ alias adb='./adb' [~/android-sdk-linux_x86/platform-tools]$ adb shell mkdir /data/bin [~/android-sdk-linux_x86/platform-tools]$ adb push ~/Downloads/android-tar /data/bin/tar [~/android-sdk-linux_x86/platform-tools]$ adb push ~/temp/sysroot.tar /data/sysroot.tar
in the separate terminal window (where we invoked the emulator), extract the files using the command line on the target:
# PATH=$PATH:/data/bin # export PATH # alias ls='ls -l' # cd /data # chmod 0777 ./bin/tar # tar -xf sysroot.tar # ls sysroot drwxr-xr-x system system 2011-02-27 08:22 usr drwxr-xr-x system system 2011-02-27 08:32 sbin drwxr-xr-x system system 2011-02-27 08:32 lib #At this point, all the shared libraries are in place, and we're ready to test a C++ program.
[~/]$ mkdir src [~/]$ cd src
Here's an example build script (name 'build++.sh') which contains the minimal command-line options:
#!/bin/bash arm-none-linux-gnueabi-g++ -march=armv4t \ -Wl,-rpath=/data/sysroot/lib:/data/sysroot/usr/lib \ -Wl,--dynamic-linker=/data/sysroot/lib/ld-linux.so.3 \ -ohello++ hello.cpp
And here is the source file ('hello.cpp') to build:
#include <iostream> #include <typeinfo> class sample { }; int main() { const char banner[] = "Hello World ++:"; const int myexception = 13; std::cout << banner << std::endl ; sample *ptr = 0; std::cout << "RTTI sample name is '" << typeid(ptr).name() << "'" << std::endl ; try { throw myexception; } catch (int x) { std::cerr << "Caught exception (" << x << ")" << std::endl ; } return 0; }Now let's build it, and transfer the binary to the Android-based target.
[~/src/]$ chmod +x ./build++.sh [~/src/]$ ./build++.sh [~/src/]$ cd ~/android-sdk-linux_x86/platform-tools [~/android-sdk-linux_x86/platform-tools]$ ./adb push ~/src/hello++ /data/hello++Now that we have the executable on the target, we set the mode, and run the program.
# cd /data # chmod 0777 ./hello++ # ./hello++ Hello World ++: RTTI sample name is 'P6sample' Caught exception (13) #So, that's it -- we have a full C++ runtime on the Android-based target, and we have verified it is functional.
Also, you're welcome to visit my home page.