The following patch for the python-build sub-directory allows you to cross-compile Py4A for the x86 architecture. The patch consists in:
- Adding a set of new files to support the x86 architecture (including creating a new libffi/linux-x86/ directory):
libffi/linux-x86/ffi.h
libffi/linux-x86/fficonfig.h
setup-x86.cfg - changing the build.sh script to accept a new parameter - the Android ABI (for example 'armeabi' or 'x86') - so that the script can call
ndk-build APP_ABI:=x86
to trigger the cross-compilation for the x86 processor; - changing the build.py script to parametrize the GCC strip command and the selection of the setup.cfg configuration file based on the input ABI;
- changing the libffi/Android.mk makefile to select the right set of source files based on the input ABI;
- changing the libffi/include/ffi_real.h header file to redefine FFI_TYPE_LONGDOUBLE to 4;
- changing the openssl/crypto/Android.mk and openssl/ssl/Android.mk makefiles to strip down the openssl library with only the bare minimum set that allows you to cross-compile the source code;
- changing the python/jni/modules.mk makefile to add the -fno-stack-protector compiler and linker option when building the _socket module and exclude the openssl module.
$ cd python-build
$ ./build.sh x86 Binaries for the x86 can be downloaded here:
--- orig/python/jni/modules.mk 2013-01-21 14:39:56.000000000 -0500
+++ python/jni/modules.mk 2013-01-29 14:58:52.922096000 -0500
@@ -58,7 +58,7 @@ $(call build-module, syslog , Modules/
$(call build-module, audioop , Modules/audioop.c )
$(call build-module, imageop , Modules/imageop.c )
$(call build-module, _csv , Modules/_csv.c )
-$(call build-module, _socket , Modules/socketmodule.c, libc, -lc, -nostdlib )
+$(call build-module, _socket , Modules/socketmodule.c, libc, -lc -fno-stack-protector, -nostdlib -fno-stack-protector )
$(call build-module, _sha , Modules/shamodule.c )
$(call build-module, _md5 , Modules/md5module.c Modules/md5.c )
$(call build-module, _sha256 , Modules/sha256module.c )
@@ -125,6 +125,7 @@ include $(BUILD_SHARED_LIBRARY)
#$(call build-module, _ssl , Modules/_ssl.c, ssl crypto )
+ifneq ($(APP_ABI), x86)
$(call import-module, openssl)
LOCAL_PATH := $(PYTHON_SRC_PATH)
LOCAL_C_INCLUDES += $(PYTHON_SRC_PATH) $(PYTHON_SRC_PATH)/Include $(OPENSSL)/include $(OPENSSL)
@@ -133,6 +134,7 @@ LOCAL_MODULE_FILENAME := _ssl
LOCAL_SRC_FILES := Modules/_ssl.c
LOCAL_SHARED_LIBRARIES := libpython2.6 libcrypto libssl
include $(BUILD_SHARED_LIBRARY)
+endif
$(call import-module, libffi)
--- orig/setup-x86.cfg 1969-12-31 19:00:00.000000000 -0500
+++ setup-x86.cfg 2013-01-28 16:09:49.004463929 -0500
@@ -0,0 +1,2 @@
+[bdist_egg]
+plat-name=linux-x86
--- orig/openssl/ssl/Android.mk 2013-01-21 14:42:17.000000000 -0500
+++ openssl/ssl/Android.mk 2013-01-28 16:33:35.563643087 -0500
@@ -7,6 +7,10 @@ local_c_includes := \
include $(CLEAR_VARS)
+ifeq ($(APP_ABI), x86)
+LOCAL_SRC_FILES:= \
+ kssl.c
+else
LOCAL_SRC_FILES:= \
s2_meth.c \
s2_srvr.c \
@@ -45,6 +49,7 @@ LOCAL_SRC_FILES:= \
bio_ssl.c \
ssl_err.c \
kssl.c
+endif
include $(LOCAL_PATH)/../android-config.mk
--- orig/openssl/crypto/Android.mk 2013-01-21 14:42:08.000000000 -0500
+++ openssl/crypto/Android.mk 2013-01-29 14:49:00.334324159 -0500
@@ -2,27 +2,17 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CFLAGS += -DOPENSSL_BN_ASM_MONT -DAES_ASM -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DOPENSSL_NO_STATIC_ENGINE
+ifneq ($(APP_ABI), x86)
LOCAL_SRC_FILES:= 0.9.9-dev/bn/armv4-mont.s \
0.9.9-dev/aes/aes-armv4.s \
0.9.9-dev/sha/sha1-armv4-large.s \
0.9.9-dev/sha/sha256-armv4.s \
0.9.9-dev/sha/sha512-armv4.s
-
LOCAL_SRC_FILES+= \
- cryptlib.c \
- mem.c \
- mem_clr.c \
mem_dbg.c \
- cversion.c \
dyn_lck.c \
ex_data.c \
- tmdiff.c \
cpt_err.c \
- ebcdic.c \
- uid.c \
- o_time.c \
- o_str.c \
- o_dir.c \
aes/aes_misc.c \
aes/aes_ecb.c \
aes/aes_cbc.c \
@@ -474,6 +464,19 @@ LOCAL_SRC_FILES+= \
ripemd/rmd_dgst.c \
ripemd/rmd_one.c \
evp/m_ripemd.c
+endif
+
+LOCAL_SRC_FILES+= \
+ cryptlib.c \
+ mem.c \
+ mem_clr.c \
+ cversion.c \
+ tmdiff.c \
+ ebcdic.c \
+ uid.c \
+ o_time.c \
+ o_str.c \
+ o_dir.c
LOCAL_CFLAGS += -DNO_WINDOWS_BRAINDEATH
--- orig/build.py 2013-01-21 14:44:17.000000000 -0500
+++ build.py 2013-01-28 16:19:35.088015089 -0500
@@ -82,6 +82,10 @@ def rm(path):
def strip(path):
+ if len(sys.argv) > 1:
+ if sys.argv[1] == "x86":
+ run('i686-linux-android-strip %s' % path)
+ else:
run('arm-linux-androideabi-strip %s' % path)
@@ -153,6 +157,12 @@ map(rm, find('output.temp/usr/lib/python
map(rm, find('output.temp', 'python$', exclude=['setuptools', 'distutils'])[0])
run("mkdir python", cwd="output.temp/usr")
run("cp -r %s/python-libs/py4a python" % pwd, cwd="output.temp/usr")
+if len(sys.argv) > 1:
+ if sys.argv[1] == "x86":
+ run("cp %s/setup-x86.cfg ." % pwd, cwd="output.temp/usr")
+ else:
+ run("cp %s/setup.cfg ." % pwd, cwd="output.temp/usr")
+else:
run("cp %s/setup.cfg ." % pwd, cwd="output.temp/usr")
run("cp %s/prepare_setuptools.sh setup.sh" % pwd, cwd="output.temp/usr")
run("cp %s/standalone_python.sh python.sh" % pwd, cwd="output.temp/usr")
--- orig/libffi/include/ffi_real.h 2013-01-21 14:42:35.000000000 -0500
+++ libffi/include/ffi_real.h 2013-01-29 10:27:30.664550823 -0500
@@ -371,8 +371,12 @@ void ffi_call(ffi_cif *cif,
#if CONF_HAVE_LONG_DOUBLE // android changed
#define FFI_TYPE_LONGDOUBLE 4
#else
+#ifdef x86
+#define FFI_TYPE_LONGDOUBLE 4
+#else
#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
#endif
+#endif
#define FFI_TYPE_UINT8 5
#define FFI_TYPE_SINT8 6
#define FFI_TYPE_UINT16 7
--- orig/libffi/Android.mk 2013-01-21 14:42:42.000000000 -0500
+++ libffi/Android.mk 2013-01-28 17:00:21.190897854 -0500
@@ -21,6 +21,17 @@ include $(CLEAR_VARS)
LOCAL_MODULE := ffi
LOCAL_MODULE_FILENAME :=
+ifeq ($(APP_ABI), x86)
+ LOCAL_SRC_FILES := src/x86/sysv.S \
+ src/x86/ffi.c \
+ src/debug.c \
+ src/java_raw_api.c \
+ src/prep_cif.c \
+ src/raw_api.c \
+ src/types.c
+
+ LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/linux-x86
+else
LOCAL_SRC_FILES := src/arm/sysv.S \
src/arm/ffi.c \
src/debug.c \
@@ -30,6 +41,7 @@ LOCAL_SRC_FILES := src/arm/sysv.S \
src/types.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(LOCAL_PATH)/linux-arm
+endif
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
$(call __ndk_info, Building libffi)
--- orig/libffi/linux-x86/ffi.h 1969-12-31 19:00:00.000000000 -0500
+++ libffi/linux-x86/ffi.h 2013-01-28 16:24:28.975890002 -0500
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2008 The Android Open Source Project
+ */
+#ifndef LIBFFI_H
+
+#define x86
+#include "../src/x86/ffitarget.h"
+#include "../include/ffi_real.h"
+
+#endif
--- orig/libffi/linux-x86/fficonfig.h 1969-12-31 19:00:00.000000000 -0500
+++ libffi/linux-x86/fficonfig.h 2013-01-28 16:23:04.047926730 -0500
@@ -0,0 +1,160 @@
+/* fficonfig.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
+ systems. This function is required for `alloca.c' support on those systems.
+ */
+#undef CRAY_STACKSEG_END
+
+/* Define to 1 if using `alloca.c'. */
+#undef C_ALLOCA
+
+/* Define to the flags needed for the .section .eh_frame directive. */
+#define EH_FRAME_FLAGS "aw"
+
+/* Define this if you want extra debugging. */
+#undef FFI_DEBUG
+
+/* Define this is you do not want support for the raw API. */
+#undef FFI_NO_RAW_API
+
+/* Define this is you do not want support for aggregate types. */
+#undef FFI_NO_STRUCTS
+
+/* Define to 1 if you have `alloca', as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
+ */
+#define HAVE_ALLOCA_H 1
+
+/* Define if your assembler supports .cfi_* directives. */
+#undef HAVE_AS_CFI_PSEUDO_OP
+
+/* Define if your assembler supports .register. */
+#undef HAVE_AS_REGISTER_PSEUDO_OP
+
+/* Define if your assembler and linker support unaligned PC relative relocs.
+ */
+#undef HAVE_AS_SPARC_UA_PCREL
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if __attribute__((visibility("hidden"))) is supported. */
+#undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have the long double type and it is bigger than a double */
+#undef HAVE_LONG_DOUBLE
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mmap' function. */
+#define HAVE_MMAP 1
+
+/* Define if mmap with MAP_ANON(YMOUS) works. */
+#define HAVE_MMAP_ANON 1
+
+/* Define if mmap of /dev/zero works. */
+#define HAVE_MMAP_DEV_ZERO 1
+
+/* Define if read-only mmap of a plain file works. */
+#define HAVE_MMAP_FILE 1
+
+/* Define if .eh_frame sections should be read-only. */
+#undef HAVE_RO_EH_FRAME
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#define HAVE_SYS_MMAN_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+#undef NO_MINUS_C_MINUS_O
+
+/* Name of package */
+#define PACKAGE "libffi"
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* The size of `double', as computed by sizeof. */
+#define SIZEOF_DOUBLE 8
+
+/* The size of `long double', as computed by sizeof. */
+#undef SIZEOF_LONG_DOUBLE
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at runtime.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+#undef STACK_DIRECTION
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define this if you are using Purify and want to suppress spurious messages.
+ */
+#undef USING_PURIFY
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if your processor stores words with the most significant byte
+ first (like Motorola and SPARC, unlike Intel and VAX). */
+#undef WORDS_BIGENDIAN
+
+
+#ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE
+#ifdef LIBFFI_ASM
+#define FFI_HIDDEN(name) .hidden name
+#else
+#define FFI_HIDDEN __attribute__ ((visibility ("hidden")))
+#endif
+#else
+#ifdef LIBFFI_ASM
+#define FFI_HIDDEN(name)
+#else
+#define FFI_HIDDEN
+#endif
+#endif
+
--- build.sh (orig/build.sh)
+++ build.sh (build.sh)
@@ -5,6 +5,7 @@
set -ex
CWD=$(pwd)
DEBUG=no
+android_abi="$1"
RELEASE_VERSION=$(cat LATEST_VERSION)
echo "Building Python VM For Android Release ${RELEASE_VERSION}"
@@ -78,12 +79,12 @@
${CWD}/host/pgen ${CWD}/python-src/Grammar/Grammar \
${CWD}/python-src/Include/graminit.h \
${CWD}/python-src/Python/graminit.c
-ndk-build
+ndk-build APP_ABI:=$android_abi
# copy out all the needed files
-mv obj/local/armeabi/python ${OUT}/usr/bin
-mv obj/local/armeabi/lib*.so ${OUT}/usr/lib
-mv obj/local/armeabi/*.so ${OUT}/usr/lib/python2.6/lib-dynload
+mv obj/local/$android_abi/python ${OUT}/usr/bin
+mv obj/local/$android_abi/lib*.so ${OUT}/usr/lib
+mv obj/local/$android_abi/*.so ${OUT}/usr/lib/python2.6/lib-dynload
popd
pushd ${CWD}/python-libs
@@ -91,7 +92,7 @@
popd
${CWD}/host/bin/python ${OUT}/usr/lib/python2.6/compileall.py ${OUT}/usr/lib/python2.6
-${CWD}/host/bin/python build.py
+${CWD}/host/bin/python build.py $android_abi
if [ "$DEBUG" != "yes" ]; then
rm -rf output*
Hi!
ReplyDeleteThanks for the blog post explaining how to compile python for Android x86.
Would it be possible for you to release a binary package as well?
Thanks
I updated the post by adding links to the zipped x86 binaries (see above).
DeleteHi -
ReplyDeleteFollow up question: is it possible that your patch is missing the changes for build.sh where it takes the parameter defining the target architecture (x86 vs ARM)?
Thanks
I just updated the post to add the patch for the build.sh script at the bottom.
DeleteFantastic, thanks! I'll give it a try and let you know how it goes.
DeleteDid you ever have any success building python 2.7+ for Android x86 using a similar approach?
ReplyDeleteBrad,
Deleteno, I didn't try to build any recent version of Python for Android x86.