android: some changes for building on Android:

- allow setting API target with --target=android-21
 - always link to libpython on Android, seems to be necessary
 - support aarch64 (arm64-v8 ABI) architecture
 - enable building on an Android machine (tested in termux)

[skip ci]
This commit is contained in:
rdb 2018-01-28 14:14:53 +01:00
parent 04352e152d
commit 60a572f88a
3 changed files with 80 additions and 25 deletions

View File

@ -51,6 +51,8 @@
#elif defined(__ANDROID__) #elif defined(__ANDROID__)
#if defined(__ARM_ARCH_7A__) #if defined(__ARM_ARCH_7A__)
#define DTOOL_PLATFORM "android_armv7a" #define DTOOL_PLATFORM "android_armv7a"
#elif defined(__aarch64__)
#define DTOOL_PLATFORM "android_aarch64"
#elif defined(__arm__) #elif defined(__arm__)
#define DTOOL_PLATFORM "android_arm" #define DTOOL_PLATFORM "android_arm"
#elif defined(__mips__) #elif defined(__mips__)

View File

@ -864,7 +864,7 @@ if (COMPILER=="GCC"):
if not PkgSkip("PYTHON"): if not PkgSkip("PYTHON"):
python_lib = SDK["PYTHONVERSION"] python_lib = SDK["PYTHONVERSION"]
if not RTDIST: if not RTDIST and GetTarget() != 'android':
# We don't link anything in the SDK with libpython. # We don't link anything in the SDK with libpython.
python_lib = "" python_lib = ""
SmartPkgEnable("PYTHON", "", python_lib, (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h")) SmartPkgEnable("PYTHON", "", python_lib, (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h"))
@ -1259,6 +1259,9 @@ def CompileCxx(obj,src,opts):
if GetTarget() == "android": if GetTarget() == "android":
# Most of the specific optimization flags here were # Most of the specific optimization flags here were
# just copied from the default Android Makefiles. # just copied from the default Android Makefiles.
if "ANDROID_API" in SDK:
cmd += ' -D__ANDROID_API__=' + str(SDK["ANDROID_API"])
if "ANDROID_STL" in SDK:
cmd += ' -I%s/include' % (SDK["ANDROID_STL"]) cmd += ' -I%s/include' % (SDK["ANDROID_STL"])
cmd += ' -I%s/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"]) cmd += ' -I%s/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"])
cmd += ' -ffunction-sections -funwind-tables' cmd += ' -ffunction-sections -funwind-tables'
@ -1310,7 +1313,7 @@ def CompileCxx(obj,src,opts):
if optlevel >= 4 or GetTarget() == "android": if optlevel >= 4 or GetTarget() == "android":
cmd += " -fno-rtti" cmd += " -fno-rtti"
if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm"): if ('SSE2' in opts or not PkgSkip("SSE2")) and not arch.startswith("arm") and arch != 'aarch64':
cmd += " -msse2" cmd += " -msse2"
# Needed by both Python, Panda, Eigen, all of which break aliasing rules. # Needed by both Python, Panda, Eigen, all of which break aliasing rules.
@ -1437,12 +1440,19 @@ def CompileIgate(woutd,wsrc,opts):
cmd += ' -D_MSC_VER=1600 -D"__declspec(param)=" -D__cdecl -D_near -D_far -D__near -D__far -D__stdcall' cmd += ' -D_MSC_VER=1600 -D"__declspec(param)=" -D__cdecl -D_near -D_far -D__near -D__far -D__stdcall'
if (COMPILER=="GCC"): if (COMPILER=="GCC"):
cmd += ' -D__attribute__\(x\)=' cmd += ' -D__attribute__\(x\)='
if GetTargetArch() in ("x86_64", "amd64"): target_arch = GetTargetArch()
if target_arch in ("x86_64", "amd64"):
cmd += ' -D_LP64' cmd += ' -D_LP64'
elif target_arch == 'aarch64':
cmd += ' -D_LP64 -D__LP64__ -D__aarch64__'
else: else:
cmd += ' -D__i386__' cmd += ' -D__i386__'
if GetTarget() == 'darwin':
target = GetTarget()
if target == 'darwin':
cmd += ' -D__APPLE__' cmd += ' -D__APPLE__'
elif target == 'android':
cmd += ' -D__ANDROID__'
optlevel = GetOptimizeOption(opts) optlevel = GetOptimizeOption(opts)
if (optlevel==1): cmd += ' -D_DEBUG' if (optlevel==1): cmd += ' -D_DEBUG'
@ -1744,8 +1754,8 @@ def CompileLink(dll, obj, opts):
if LDFLAGS != "": if LDFLAGS != "":
cmd += " " + LDFLAGS cmd += " " + LDFLAGS
# Don't link libraries with Python. # Don't link libraries with Python, except on Android.
if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST: if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST and GetTarget() != 'android':
opts = opts[:] opts = opts[:]
opts.remove("PYTHON") opts.remove("PYTHON")

View File

@ -37,6 +37,7 @@ TARGET_ARCH = None
HAS_TARGET_ARCH = False HAS_TARGET_ARCH = False
TOOLCHAIN_PREFIX = "" TOOLCHAIN_PREFIX = ""
ANDROID_ABI = None ANDROID_ABI = None
ANDROID_API = 14
SYS_LIB_DIRS = [] SYS_LIB_DIRS = []
SYS_INC_DIRS = [] SYS_INC_DIRS = []
DEBUG_DEPENDENCIES = False DEBUG_DEPENDENCIES = False
@ -290,6 +291,12 @@ def GetHost():
elif sys.platform == 'darwin': elif sys.platform == 'darwin':
return 'darwin' return 'darwin'
elif sys.platform.startswith('linux'): elif sys.platform.startswith('linux'):
try:
# Python seems to offer no built-in way to check this.
osname = subprocess.check_output(["uname", "-o"])
if osname.strip().lower() == b'android':
return 'android'
except:
return 'linux' return 'linux'
elif sys.platform.startswith('freebsd'): elif sys.platform.startswith('freebsd'):
return 'freebsd' return 'freebsd'
@ -344,10 +351,20 @@ def SetTarget(target, arch=None):
if arch not in choices: if arch not in choices:
exit('Mac OS X architecture must be one of %s' % (', '.join(choices))) exit('Mac OS X architecture must be one of %s' % (', '.join(choices)))
elif target == 'android': elif target == 'android' or target.startswith('android-'):
if arch is None: if arch is None:
# If compiling on Android, default to same architecture. Otherwise, arm.
if host == 'android':
arch = host_arch
else:
arch = 'arm' arch = 'arm'
# Did we specify an API level?
target, _, api = target.partition('-')
if api:
global ANDROID_API
ANDROID_API = int(api)
# Determine the prefix for our gcc tools, eg. arm-linux-androideabi-gcc # Determine the prefix for our gcc tools, eg. arm-linux-androideabi-gcc
global ANDROID_ABI global ANDROID_ABI
if arch == 'armv7a': if arch == 'armv7a':
@ -356,14 +373,23 @@ def SetTarget(target, arch=None):
elif arch == 'arm': elif arch == 'arm':
ANDROID_ABI = 'armeabi' ANDROID_ABI = 'armeabi'
TOOLCHAIN_PREFIX = 'arm-linux-androideabi-' TOOLCHAIN_PREFIX = 'arm-linux-androideabi-'
elif arch == 'x86': elif arch == 'aarch64':
ANDROID_ABI = 'x86' ANDROID_ABI = 'arm64-v8a'
TOOLCHAIN_PREFIX = 'i686-linux-android-' TOOLCHAIN_PREFIX = 'aarch64-linux-android-'
elif arch == 'mips': elif arch == 'mips':
ANDROID_ABI = 'mips' ANDROID_ABI = 'mips'
TOOLCHAIN_PREFIX = 'mipsel-linux-android-' TOOLCHAIN_PREFIX = 'mipsel-linux-android-'
elif arch == 'mips64':
ANDROID_ABI = 'mips64'
TOOLCHAIN_PREFIX = 'mips64el-linux-android-'
elif arch == 'x86':
ANDROID_ABI = 'x86'
TOOLCHAIN_PREFIX = 'i686-linux-android-'
elif arch == 'x86_64':
ANDROID_ABI = 'x86_64'
TOOLCHAIN_PREFIX = 'x86_64-linux-android-'
else: else:
exit('Android architecture must be arm, armv7a, x86 or mips') exit('Android architecture must be arm, armv7a, aarch64, mips, mips64, x86 or x86_64')
elif target == 'linux': elif target == 'linux':
if arch is not None: if arch is not None:
@ -413,13 +439,13 @@ def CrossCompiling():
return GetTarget() != GetHost() return GetTarget() != GetHost()
def GetCC(): def GetCC():
if TARGET == 'darwin' or TARGET == 'freebsd': if TARGET in ('darwin', 'freebsd', 'android'):
return os.environ.get('CC', TOOLCHAIN_PREFIX + 'clang') return os.environ.get('CC', TOOLCHAIN_PREFIX + 'clang')
else: else:
return os.environ.get('CC', TOOLCHAIN_PREFIX + 'gcc') return os.environ.get('CC', TOOLCHAIN_PREFIX + 'gcc')
def GetCXX(): def GetCXX():
if TARGET == 'darwin' or TARGET == 'freebsd': if TARGET in ('darwin', 'freebsd', 'android'):
return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'clang++') return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'clang++')
else: else:
return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'g++') return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'g++')
@ -2339,6 +2365,16 @@ def SdkLocateAndroid():
if GetTarget() != 'android': if GetTarget() != 'android':
return return
# Allow ANDROID_API/ANDROID_ABI to be used in makepanda.py.
api = ANDROID_API
SDK["ANDROID_API"] = api
abi = ANDROID_ABI
SDK["ANDROID_ABI"] = abi
if GetHost() == 'android':
return
# Determine the NDK installation directory. # Determine the NDK installation directory.
if 'NDK_ROOT' not in os.environ: if 'NDK_ROOT' not in os.environ:
exit('NDK_ROOT must be set when compiling for Android!') exit('NDK_ROOT must be set when compiling for Android!')
@ -2355,18 +2391,20 @@ def SdkLocateAndroid():
if arch == 'armv7a' or arch == 'arm': if arch == 'armv7a' or arch == 'arm':
arch = 'arm' arch = 'arm'
toolchain = 'arm-linux-androideabi-' + gcc_ver toolchain = 'arm-linux-androideabi-' + gcc_ver
elif arch == 'x86': elif arch == 'aarch64':
toolchain = 'x86-' + gcc_ver toolchain = 'aarch64-linux-android-' + gcc_ver
elif arch == 'mips': elif arch == 'mips':
toolchain = 'mipsel-linux-android-' + gcc_ver toolchain = 'mipsel-linux-android-' + gcc_ver
elif arch == 'mips64':
toolchain = 'mips64el-linux-android-' + gcc_ver
elif arch == 'x86':
toolchain = 'x86-' + gcc_ver
elif arch == 'x86_64':
toolchain = 'x86_64-' + gcc_ver
SDK["ANDROID_TOOLCHAIN"] = os.path.join(ndk_root, 'toolchains', toolchain) SDK["ANDROID_TOOLCHAIN"] = os.path.join(ndk_root, 'toolchains', toolchain)
# Allow ANDROID_ABI to be used in makepanda.py.
abi = ANDROID_ABI
SDK["ANDROID_ABI"] = abi
# Determine the sysroot directory. # Determine the sysroot directory.
SDK["SYSROOT"] = os.path.join(ndk_root, 'platforms', 'android-9', 'arch-%s' % (arch)) SDK["SYSROOT"] = os.path.join(ndk_root, 'platforms', 'android-%s' % (api), 'arch-%s' % (arch))
#IncDirectory("ALWAYS", os.path.join(SDK["SYSROOT"], 'usr', 'include')) #IncDirectory("ALWAYS", os.path.join(SDK["SYSROOT"], 'usr', 'include'))
stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'gnu-libstdc++', gcc_ver) stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'gnu-libstdc++', gcc_ver)
@ -2626,7 +2664,12 @@ def SetupBuildEnvironment(compiler):
print("Using compiler: %s" % compiler) print("Using compiler: %s" % compiler)
print("Host OS: %s" % GetHost()) print("Host OS: %s" % GetHost())
print("Host arch: %s" % GetHostArch()) print("Host arch: %s" % GetHostArch())
target = GetTarget()
if target != 'android':
print("Target OS: %s" % GetTarget()) print("Target OS: %s" % GetTarget())
else:
print("Target OS: %s (API level %d)" % (GetTarget(), ANDROID_API))
print("Target arch: %s" % GetTargetArch()) print("Target arch: %s" % GetTargetArch())
# Set to English so we can safely parse the result of gcc commands. # Set to English so we can safely parse the result of gcc commands.
@ -2732,7 +2775,7 @@ def SetupBuildEnvironment(compiler):
print(" " + dir) print(" " + dir)
# In the case of Android, we have to put the toolchain on the PATH in order to use it. # In the case of Android, we have to put the toolchain on the PATH in order to use it.
if GetTarget() == 'android': if GetTarget() == 'android' and GetHost() != 'android':
# Locate the directory where the toolchain binaries reside. # Locate the directory where the toolchain binaries reside.
prebuilt_dir = os.path.join(SDK['ANDROID_TOOLCHAIN'], 'prebuilt') prebuilt_dir = os.path.join(SDK['ANDROID_TOOLCHAIN'], 'prebuilt')
if not os.path.isdir(prebuilt_dir): if not os.path.isdir(prebuilt_dir):