Here's an early Christmas present for all those Python fanatics (self included) out there! With a lot of help from my friends (thanks Manuel and Thomas!) I managed to install Python 2.4.5 on my G1. It's still rough around the edges, but I think it's a good start. Klaus Reimer has a nice overview of how to cross-compile Python. My instructions borrow a lot from his.
- Download and build the Android source. These directions assume that you have installed the source to
/android_src. - Download and build the Python 2.4.5 source. These directions assume that you have installed the source to
/python_src. - Make copies of python and pgen for use later in the build process then clean up.
$ cd /python_src
$ cp python hostpython
$ cp Parser/pgen Parser/hostpgen
$ make distclean
- Apply the following patch to the Python source.
diff -r -c -b Python-2.4.5/Makefile.pre.in Python-2.4.5-android/Makefile.pre.in
*** Python-2.4.5/Makefile.pre.in Sun Oct 8 19:41:25 2006
--- Python-2.4.5-android/Makefile.pre.in Fri Dec 19 10:02:17 2008
***************
*** 166,171 ****
--- 166,172 ----
PYTHON= python$(EXE)
BUILDPYTHON= python$(BUILDEXE)
+ HOSTPYTHON= ./$(BUILDPYTHON)
# === Definitions added by makesetup ===
***************
*** 192,197 ****
--- 193,199 ----
##########################################################################
# Parser
PGEN= Parser/pgen$(EXE)
+ HOSTPGEN= $(PGEN)
POBJS= \
Parser/acceler.o \
***************
*** 324,331 ****
# Build the shared modules
sharedmods: $(BUILDPYTHON)
case $$MAKEFLAGS in \
! *-s*) $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' ./$(BUILDPYTHON) -E $(srcdir)/setup.py -q build;; \
! *) $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' ./$(BUILDPYTHON) -E $(srcdir)/setup.py build;; \
esac
# buildno should really depend on something like LIBRARY_SRC
--- 326,333 ----
# Build the shared modules
sharedmods: $(BUILDPYTHON)
case $$MAKEFLAGS in \
! *-s*) $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' $(HOSTPYTHON) -E $(srcdir)/setup.py -q build;; \
! *) $(RUNSHARED) CC='$(CC)' LDSHARED='$(BLDSHARED)' OPT='$(OPT)' $(HOSTPYTHON) -E $(srcdir)/setup.py build;; \
esac
# buildno should really depend on something like LIBRARY_SRC
***************
*** 455,461 ****
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
! -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
$(PGEN): $(PGENOBJS)
$(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
--- 457,463 ----
$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT)
! -$(HOSTPGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C)
$(PGEN): $(PGENOBJS)
$(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN)
***************
*** 748,767 ****
done; \
done
$(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
! PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! ./$(BUILDPYTHON) -Wi -tt $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST) -f \
-x 'badsyntax|site-packages' $(DESTDIR)$(LIBDEST)
! PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! ./$(BUILDPYTHON) -Wi -tt -O $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST) -f \
-x 'badsyntax|site-packages' $(DESTDIR)$(LIBDEST)
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! ./$(BUILDPYTHON) -Wi -t $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! ./$(BUILDPYTHON) -Wi -t -O $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
--- 750,769 ----
done; \
done
$(INSTALL_DATA) $(srcdir)/LICENSE $(DESTDIR)$(LIBDEST)/LICENSE.txt
! -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! $(HOSTPYTHON) -Wi -tt $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST) -f \
-x 'badsyntax|site-packages' $(DESTDIR)$(LIBDEST)
! -PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! $(HOSTPYTHON) -Wi -tt -O $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST) -f \
-x 'badsyntax|site-packages' $(DESTDIR)$(LIBDEST)
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! $(HOSTPYTHON) -Wi -t $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
-PYTHONPATH=$(DESTDIR)$(LIBDEST) $(RUNSHARED) \
! $(HOSTPYTHON) -Wi -t -O $(DESTDIR)$(LIBDEST)/compileall.py \
-d $(LIBDEST)/site-packages -f \
-x badsyntax $(DESTDIR)$(LIBDEST)/site-packages
***************
*** 856,862 ****
# Install the dynamically loadable modules
# This goes into $(exec_prefix)
sharedinstall:
! $(RUNSHARED) ./$(BUILDPYTHON) -E $(srcdir)/setup.py install \
--prefix=$(prefix) \
--install-scripts=$(BINDIR) \
--install-platlib=$(DESTSHARED) \
--- 858,864 ----
# Install the dynamically loadable modules
# This goes into $(exec_prefix)
sharedinstall:
! $(RUNSHARED) $(HOSTPYTHON) -E $(srcdir)/setup.py install \
--prefix=$(prefix) \
--install-scripts=$(BINDIR) \
--install-platlib=$(DESTSHARED) \
diff -r -c -b Python-2.4.5/Modules/pwdmodule.c Python-2.4.5-android/Modules/pwdmodule.c
*** Python-2.4.5/Modules/pwdmodule.c Wed Sep 27 21:17:32 2006
--- Python-2.4.5-android/Modules/pwdmodule.c Fri Dec 19 10:26:14 2008
***************
*** 77,83 ****
#ifdef __VMS
SETS(setIndex++, "");
#else
! SETS(setIndex++, p->pw_gecos);
#endif
SETS(setIndex++, p->pw_dir);
SETS(setIndex++, p->pw_shell);
--- 77,83 ----
#ifdef __VMS
SETS(setIndex++, "");
#else
! SETS(setIndex++, "");//p->pw_gecos);
#endif
SETS(setIndex++, p->pw_dir);
SETS(setIndex++, p->pw_shell);
diff -r -c -b Python-2.4.5/Modules/socketmodule.c Python-2.4.5-android/Modules/socketmodule.c
*** Python-2.4.5/Modules/socketmodule.c Tue Oct 10 18:20:41 2006
--- Python-2.4.5-android/Modules/socketmodule.c Fri Dec 19 17:51:36 2008
***************
*** 61,66 ****
--- 61,67 ----
*/
+ #define INET_ADDRSTRLEN 16
#ifdef __APPLE__
/*
* inet_aton is not available on OSX 10.3, yet we want to use a binary
diff -r -c -b Python-2.4.5/Objects/fileobject.c Python-2.4.5-android/Objects/fileobject.c
*** Python-2.4.5/Objects/fileobject.c Tue Jan 23 16:09:19 2007
--- Python-2.4.5-android/Objects/fileobject.c Fri Dec 19 16:47:32 2008
***************
*** 1,5 ****
--- 1,6 ----
/* File object implementation */
+ #include "/android_src/bionic/libc/stdio/clrerr.c"
#include "Python.h"
#include "structmember.h"
diff -r -c -b Python-2.4.5/Python/pystrtod.c Python-2.4.5-android/Python/pystrtod.c
*** Python-2.4.5/Python/pystrtod.c Tue Jun 8 20:52:54 2004
--- Python-2.4.5-android/Python/pystrtod.c Fri Dec 19 10:18:11 2008
***************
*** 54,61 ****
fail_pos = NULL;
! locale_data = localeconv();
! decimal_point = locale_data->decimal_point;
decimal_point_len = strlen(decimal_point);
assert(decimal_point_len != 0);
--- 54,61 ----
fail_pos = NULL;
! //locale_data = localeconv();
! decimal_point = '.';//locale_data->decimal_point;
decimal_point_len = strlen(decimal_point);
assert(decimal_point_len != 0);
***************
*** 218,225 ****
PyOS_snprintf(buffer, buf_len, format, d);
! locale_data = localeconv();
! decimal_point = locale_data->decimal_point;
decimal_point_len = strlen(decimal_point);
assert(decimal_point_len != 0);
--- 218,225 ----
PyOS_snprintf(buffer, buf_len, format, d);
! //locale_data = localeconv();
! decimal_point = '.';//locale_data->decimal_point;
decimal_point_len = strlen(decimal_point);
assert(decimal_point_len != 0);
diff -r -c -b Python-2.4.5/setup.py Python-2.4.5-android/setup.py
*** Python-2.4.5/setup.py Sun Oct 8 19:41:25 2006
--- Python-2.4.5-android/setup.py Fri Dec 19 17:26:29 2008
***************
*** 15,21 ****
from distutils.command.install_lib import install_lib
# This global variable is used to hold the list of modules to be disabled.
! disabled_module_list = []
def add_dir_to_list(dirlist, dir):
"""Add the directory 'dir' to the list 'dirlist' (at the front) if
--- 15,33 ----
from distutils.command.install_lib import install_lib
# This global variable is used to hold the list of modules to be disabled.
! disabled_module_list = [
! '_ctypes',
! '_curses',
! '_curses_panel',
! '_locale',
! '_ssl',
! 'crypt',
! 'linuxaudiodev',
! 'nis',
! 'ossaudiodev',
! 'readline',
! 'zlib',
! ]
def add_dir_to_list(dirlist, dir):
"""Add the directory 'dir' to the list 'dirlist' (at the front) if
***************
*** 199,204 ****
--- 211,218 ----
self.announce('WARNING: skipping import check for Cygwin-based "%s"'
% ext.name)
return
+ if os.environ.get('CROSS_COMPILE') == 'yes':
+ return
ext_filename = os.path.join(
self.build_lib,
self.get_ext_filename(self.get_ext_fullname(ext.name)))
- Download agcc.
- Make a copy of
agcccalledag++and apply the following patch.
*** agcc 2008-11-06 18:22:48.000000000 +0100
--- ag++ 2008-12-19 21:19:21.000000000 +0100
***************
*** 32,41 ****
# Dance around to find the actual android toolchain path (it's very
# deep, so links on $PATH are going to be common.
! my $GCC = `which arm-eabi-gcc`;
$GCC = qx(cd `dirname $GCC`; /bin/pwd);
chomp $GCC;
! die "bad arm-eabi-gcc path" if $GCC !~ /(.*)\/prebuilt\//;
my $DROID = $1;
my $ALIB = "$DROID/out/target/product/generic/obj/lib";
--- 32,41 ----
# Dance around to find the actual android toolchain path (it's very
# deep, so links on $PATH are going to be common.
! my $GCC = `which arm-eabi-g++`;
$GCC = qx(cd `dirname $GCC`; /bin/pwd);
chomp $GCC;
! die "bad arm-eabi-g++ path" if $GCC !~ /(.*)\/prebuilt\//;
my $DROID = $1;
my $ALIB = "$DROID/out/target/product/generic/obj/lib";
***************
*** 174,180 ****
if($have_src and $mode ne "-E") { $need_cpp = $need_compile = 1; }
# Assemble the command:
! my @cmd = ("arm-eabi-gcc");
if($mode ne "DEFAULT") { @cmd = (@cmd, $mode); }
if(defined $out) { @cmd = (@cmd, "-o", $out); }
if($need_cpp) { @cmd = (@cmd, @include_paths, @preprocess_args); }
--- 174,180 ----
if($have_src and $mode ne "-E") { $need_cpp = $need_compile = 1; }
# Assemble the command:
! my @cmd = ("arm-eabi-g++");
if($mode ne "DEFAULT") { @cmd = (@cmd, $mode); }
if(defined $out) { @cmd = (@cmd, "-o", $out); }
if($need_cpp) { @cmd = (@cmd, @include_paths, @preprocess_args); }
- Add
agccandag++to your path. - Add
/android_src/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/binto your path (the Android toolchain). - Add
/android_src/out/host/linux-x86/binto your path (the Android development tools). - Reconfigure Python for Android.
$ CROSS_COMPILE=yes CXX=ag++ CC=agcc AR=arm-eabi-ar \
RANLIB=arm-eabi-ranlib LD=arm-eabi-ld AS=arm-eabi-as \
STRIP=arm-eabi-strip ./configure --host=linux --build=arm-linux --prefix=/data
- Remove the posix module from the
Makefileand from/python_src/Modules/config.cusing the following patch.
*** Python-2.4.5/Makefile Fri Dec 19 22:21:20 2008
--- Python-2.4.5-android/Makefile Fri Dec 19 22:23:50 2008
***************
*** 21,27 ****
# === Variables set by makesetup ===
! MODOBJS= Modules/threadmodule.o Modules/signalmodule.o Modules/posixmodule.o Modules/errnomodule.o Modules/pwdmodule.o Modules/_sre.o Modules/_codecsmodule.o Modules/zipimport.o Modules/symtablemodule.o Modules/xxsubtype.o
MODLIBS= $(LOCALMODLIBS) $(BASEMODLIBS)
# === Variables set by configure
--- 21,27 ----
# === Variables set by makesetup ===
! MODOBJS= Modules/threadmodule.o Modules/signalmodule.o Modules/errnomodule.o Modules/pwdmodule.o Modules/_sre.o Modules/_codecsmodule.o Modules/zipimport.o Modules/symtablemodule.o Modules/xxsubtype.o
MODLIBS= $(LOCALMODLIBS) $(BASEMODLIBS)
# === Variables set by configure
*** Python-2.4.5/Modules/config.c Fri Dec 19 22:21:20 2008
--- Python-2.4.5-android/Modules/config.c Fri Dec 19 22:26:06 2008
***************
*** 21,27 ****
extern void initthread(void);
extern void initsignal(void);
! extern void initposix(void);
extern void initerrno(void);
extern void initpwd(void);
extern void init_sre(void);
--- 21,27 ----
extern void initthread(void);
extern void initsignal(void);
! //extern void initposix(void);
extern void initerrno(void);
extern void initpwd(void);
extern void init_sre(void);
***************
*** 40,46 ****
{"thread", initthread},
{"signal", initsignal},
! {"posix", initposix},
{"errno", initerrno},
{"pwd", initpwd},
{"_sre", init_sre},
--- 40,46 ----
{"thread", initthread},
{"signal", initsignal},
! // {"posix", initposix},
{"errno", initerrno},
{"pwd", initpwd},
{"_sre", init_sre},
- Build and install Python to a local directory.
$ make install prefix=./python-android HOSTPYTHON=./hostpython \
HOSTPGEN=./Parser/hostpgen BLDSHARED="agcc -shared" CROSS_COMPILE=yes
- Remove some unnecessary files and push Python to your G1 or emulator.
$ cd ./python-androidAnd here it is.
$ rm -rf man include lib/python2.4/test
$ find . -name '*.pyc' -exec rm {} \;
$ find . -name '*.pyo' -exec rm {} \;
$ find . -type d -not -name '.' | perl -pe 's,\./,/data/,' | xargs -L1 adb shell mkdir
$ adb push . data

Update
I've uploaded the python2.4 binary I built for Android. It's missing lots of libraries, but it runs :) I haven't corrected the build instructions yet, but I'll hopefully get to that soon.
23 comments: