Friday, October 26, 2012

How to cross-compile Python for Android

When it comes to cross-compiling Python for Android, I've followed Gabriel's blog post @ http://mdqinc.com/blog/2011/09/cross-compiling-python-for-android/ and I was successful in creating an Arm-based Python executable (and related libraries) in little or no time.
Gabriel has a lot of the initial steps just verbally described, but I've come up with a shell script that allows you to automate the entire process. Of course you need to replace <path-to-android-ndk> with the directory where you have installed the NDK.
Here it goes.

ANDROID_NDK=<path-to-android-ndk>
ANDROID_ABI="armeabi-v7a"
ANDROID_NATIVE_API_LEVEL="android-8"
PYTHON_VERSION="2.6.2"


output_dir=$1
mkdir -p $output_dir
cd $output_dir
# get Python source tarball
wget http://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz

# create Python Host version
tar zxvf Python-$PYTHON_VERSION.tgz
mv Python-$PYTHON_VERSION Host-Python-$PYTHON_VERSION-src
cd Host-Python-$PYTHON_VERSION-src
./configure --prefix=$output_dir/Host-Python-$PYTHON_VERSION
make
make install

cd $output_dir
# create Python Cross-compiled version for Android
tar zxvf Python-$PYTHON_VERSION.tgz
mv Python-$PYTHON_VERSION Android-Python-$PYTHON_VERSION-src
cd Android-Python-$PYTHON_VERSION-src

# get and apply Python patch
wget -o 
Python-2.6.2-android.patch https://sites.google.com/site/dgtechblogscripts/Python-2.6.2-android.patch
patch -p0 < Python-2.6.2-android.patch
# fix setup.py
mv setup.py setup.py.orig
cat setup.py.orig | awk '{ if (NR==316) {print "    " $0} else {print $0}}' > setup.py

MY_HOSTPYTHON=$output_dir/Host-Python-$PYTHON_VERSION/bin/python
MY_HOSTPGEN=$output_dir/Host-Python-$PYTHON_VERSION-src/Parser/pgen

export ANDROID_NDK
export PATH="$ANDROID_NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/:$ANDROID_NDK:$ANDROID_NDK/tools:/usr/local/bin:/usr/bin:/bin"
export ARCH=$ANDROID_ABI
export CFLAGS="-DANDROID -mandroid -fomit-frame-pointer --sysroot $ANDROID_NDK/platforms/$ANDROID_NATIVE_API_LEVEL/arch-arm"
export CXXFLAGS="$CFLAGS"
export CC="arm-linux-androideabi-gcc $CFLAGS"
export CXX="arm-linux-androideabi-g++ $CXXFLAGS"
export AR="arm-linux-androideabi-ar"
export RANLIB="arm-linux-androideabi-ranlib"
export STRIP="arm-linux-androideabi-strip --strip-unneeded"
export MAKE="make -j4 install HOSTPYTHON=$MY_HOSTPYTHON HOSTPGEN=$MY_HOSTPGEN CROSS_COMPILE=arm-eabi- CROSS_COMPILE_TARGET=yes"

./configure LDFLAGS="-Wl,--allow-shlib-undefined" CFLAGS="-mandroid -fomit-frame-pointer --sysroot $ANDROID_NDK/platforms/$ANDROID_NATIVE_API_LEVEL/arch-arm" HOSTPYTHON=$MY_HOSTPYTHON HOSTPGEN=$MY_HOSTPGEN --host=arm-eabi --build=i686-pc-linux-gnu --enable-shared --prefix="$output_dir/Android-Python-$PYTHON_VERSION"
sed -i "s|^INSTSONAME=\(.*.so\).*|INSTSONAME=\\1|g" Makefile
$MAKE

 



9 comments:

  1. Hi, Danilo!

    Thanks for the post.

    I tried to run your script but the patch file was not found on the link you provided inside the script.

    Even whether I change the link to a valid one (python.android.diff) it start applying the patch but takes forever and never ends.

    Skipping the patching, at the end almost finishing (without the patch) it complains about C compiler not being able to create the executables files and finally, to the final blow, it says something 'bout not finding the install file.

    Any ideas?

    Thanks in advance!

    ReplyDelete
    Replies
    1. Robert,
      the patch is necessary to avoid any compilation errors you are seeing. I realize the patch mentioned above was removed from the referenced blog. Luckily I've saved the previous Python 2.6.2 patch (download it here: https://sites.google.com/site/dgtechblogscripts/Python-2.6.2-android.patch). Of course you will also have to set the PYTHON_VERSION variable to 2.6.2. I'm going to update my blog post to reflect the changes.

      Delete
  2. Another question: Doing the procedure above, will I be able to use Python more-or-less like in my PC/MAC?

    Like, I recently used "QPython" but it has some issues: It doesn't allow input (as of raw_input() or input()) plus the console provided by it has quite a few customizing options. It doesn't even let you alter the font size or color.

    My goal is to use Python in my Samsung Galaxy Tab 2 7.0 for learning purposes.

    I only want to shorten the pain of this process if it's not going to help me in any way.

    Ty

    ReplyDelete
    Replies
    1. Robert,
      cross-compiling Python for Android as described in this postI had exactly the problem you mention of not allowing input. So I eventually downloaded and cross-compile Python-4-Android which instead works like a charm and allows you to run Python on your phone like being on a desktop. See all my other posts about Python-4-Android. Once I had the binaries for Python, I copied them on my phone using an scp client and with SSHDroid server running on the phone. Since Android does not have the equivalent of a /usr/bin directory where to install Python, you have to set the PYTHONPATH, PYTHONHOME and LD_LIBRARY_PATH environment variables to make it work seamlessly. But once you do dat you can just run python from a shell terminal (assuming you still use SSHDroid to connect to the phone via ssh), and then type in your commands like you were running from a Linux box.
      I'll probably post something about how to install and run Python4Android on your own and not rely on the GUI that comes with the program (it's kind of too small to do actual work directly on the phone).

      Delete
  3. Have you done any work on a 3.4 version? Has anyone created a patch file for it?

    ReplyDelete
    Replies
    1. Mr. B,

      no I don't have a patch for version 3.4 and I don't know if others already ported that version to Android. Sorry.

      Delete
  4. Here is my shell script with modified the ndk path, patch wget and patch flag to -p1 and the PATH="$ANDROID_NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86/bin/

    ANDROID_NDK=/home/seed/Downloads/android-ndk-r10e
    ANDROID_ABI="armeabi-v7a"
    ANDROID_NATIVE_API_LEVEL="android-8"
    PYTHON_VERSION="2.6.2"

    output_dir=$1
    mkdir -p $output_dir
    cd $output_dir
    # get Python source tarball
    wget http://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz

    # create Python Host version
    tar zxvf Python-$PYTHON_VERSION.tgz
    mv Python-$PYTHON_VERSION Host-Python-$PYTHON_VERSION-src
    cd Host-Python-$PYTHON_VERSION-src
    ./configure --prefix=$output_dir/Host-Python-$PYTHON_VERSION
    make
    make install

    cd $output_dir
    # create Python Cross-compiled version for Android
    tar zxvf Python-$PYTHON_VERSION.tgz
    mv Python-$PYTHON_VERSION Android-Python-$PYTHON_VERSION-src
    cd Android-Python-$PYTHON_VERSION-src

    # get and apply Python patch
    wget -o PythonPatch https://sites.google.com/site/dgtechblogscripts/Python-2.6.2-android.patch
    patch -p1 < Python-2.6.2-android.patch
    # fix setup.py
    mv setup.py setup.py.orig
    cat setup.py.orig | awk '{ if (NR==316) {print " " $0} else {print $0}}' > setup.py

    MY_HOSTPYTHON=$output_dir/Host-Python-$PYTHON_VERSION/bin/python
    MY_HOSTPGEN=$output_dir/Host-Python-$PYTHON_VERSION-src/Parser/pgen

    export ANDROID_NDK
    export PATH="$ANDROID_NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86/bin/:$ANDROID_NDK:$ANDROID_NDK/tools:/usr/local/bin:/usr/bin:/bin"
    export ARCH=$ANDROID_ABI
    export CFLAGS="-DANDROID -mandroid -fomit-frame-pointer --sysroot $ANDROID_NDK/platforms/$ANDROID_NATIVE_API_LEVEL/arch-arm"
    export CXXFLAGS="$CFLAGS"
    export CC="arm-linux-androideabi-gcc $CFLAGS"
    export CXX="arm-linux-androideabi-g++ $CXXFLAGS"
    export AR="arm-linux-androideabi-ar"
    export RANLIB="arm-linux-androideabi-ranlib"
    export STRIP="arm-linux-androideabi-strip --strip-unneeded"
    export MAKE="make -j4 install HOSTPYTHON=$MY_HOSTPYTHON HOSTPGEN=$MY_HOSTPGEN CROSS_COMPILE=arm-eabi- CROSS_COMPILE_TARGET=yes"

    ./configure LDFLAGS="-Wl,--allow-shlib-undefined" CFLAGS="-mandroid -fomit-frame-pointer --sysroot $ANDROID_NDK/platforms/$ANDROID_NATIVE_API_LEVEL/arch-arm" HOSTPYTHON=$MY_HOSTPYTHON HOSTPGEN=$MY_HOSTPGEN --host=arm-eabi --build=i686-pc-linux-gnu --enable-shared --prefix="$output_dir/Android-Python-$PYTHON_VERSION"
    sed -i "s|^INSTSONAME=\(.*.so\).*|INSTSONAME=\\1|g" Makefile
    $MAKE

    I dont get the python executable but lead to compilation errors in the config.log file
    Can you still generate the python binary as you did is 2012 if you can please let me know how because the script or the patch is failing with errors like :

    in ./configure
    arm-linux-androideabi-gcc: error: unrecognized command line option '-V'
    arm-linux-androideabi-gcc: fatal error: no input files
    conftest.c:11:28: fatal error: ac_nonexistent.h:
    and many more in conftest.c

    Please guide me if i am doing something wrong.
    Is it that any standards that have changed that might be the cause of the errors?

    ReplyDelete
    Replies
    1. Vijayendra,
      I recently posted a better way to cross-compile Python for Android, which includes both the patched tar ball and a script to do the compilation.
      See http://danilogiulianelli.blogspot.com/2015/06/simplified-script-to-cross-compile.html

      Delete
  5. Fortran Compiler in Android NDK r10e
    http://forum.cvapp.org/viewtopic.php?f=13&t=427&sid=b456aa3afec7ff8adeed892a84a73071

    ReplyDelete