Browse Source

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]

rdb 7 years ago
parent
commit
60a572f88a
3 changed files with 80 additions and 25 deletions
  1. 2 0
      dtool/src/dtoolbase/dtool_platform.h
  2. 18 8
      makepanda/makepanda.py
  3. 60 17
      makepanda/makepandacore.py

+ 2 - 0
dtool/src/dtoolbase/dtool_platform.h

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

+ 18 - 8
makepanda/makepanda.py

@@ -864,7 +864,7 @@ if (COMPILER=="GCC"):
 
         if not PkgSkip("PYTHON"):
             python_lib = SDK["PYTHONVERSION"]
-            if not RTDIST:
+            if not RTDIST and GetTarget() != 'android':
                 # We don't link anything in the SDK with libpython.
                 python_lib = ""
             SmartPkgEnable("PYTHON", "", python_lib, (SDK["PYTHONVERSION"], SDK["PYTHONVERSION"] + "/Python.h"))
@@ -1259,8 +1259,11 @@ def CompileCxx(obj,src,opts):
         if GetTarget() == "android":
             # Most of the specific optimization flags here were
             # just copied from the default Android Makefiles.
-            cmd += ' -I%s/include' % (SDK["ANDROID_STL"])
-            cmd += ' -I%s/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"])
+            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/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"])
             cmd += ' -ffunction-sections -funwind-tables'
             if arch == 'armv7a':
                 cmd += ' -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__'
@@ -1310,7 +1313,7 @@ def CompileCxx(obj,src,opts):
                 if optlevel >= 4 or GetTarget() == "android":
                     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"
 
         # 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'
     if (COMPILER=="GCC"):
         cmd += ' -D__attribute__\(x\)='
-        if GetTargetArch() in ("x86_64", "amd64"):
+        target_arch = GetTargetArch()
+        if target_arch in ("x86_64", "amd64"):
             cmd += ' -D_LP64'
+        elif target_arch == 'aarch64':
+            cmd += ' -D_LP64 -D__LP64__ -D__aarch64__'
         else:
             cmd += ' -D__i386__'
-        if GetTarget() == 'darwin':
+
+        target = GetTarget()
+        if target == 'darwin':
             cmd += ' -D__APPLE__'
+        elif target == 'android':
+            cmd += ' -D__ANDROID__'
 
     optlevel = GetOptimizeOption(opts)
     if (optlevel==1): cmd += ' -D_DEBUG'
@@ -1744,8 +1754,8 @@ def CompileLink(dll, obj, opts):
         if LDFLAGS != "":
             cmd += " " + LDFLAGS
 
-        # Don't link libraries with Python.
-        if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST:
+        # Don't link libraries with Python, except on Android.
+        if "PYTHON" in opts and GetOrigExt(dll) != ".exe" and not RTDIST and GetTarget() != 'android':
             opts = opts[:]
             opts.remove("PYTHON")
 

+ 60 - 17
makepanda/makepandacore.py

@@ -37,6 +37,7 @@ TARGET_ARCH = None
 HAS_TARGET_ARCH = False
 TOOLCHAIN_PREFIX = ""
 ANDROID_ABI = None
+ANDROID_API = 14
 SYS_LIB_DIRS = []
 SYS_INC_DIRS = []
 DEBUG_DEPENDENCIES = False
@@ -290,7 +291,13 @@ def GetHost():
     elif sys.platform == 'darwin':
         return 'darwin'
     elif sys.platform.startswith('linux'):
-        return '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'
     elif sys.platform.startswith('freebsd'):
         return 'freebsd'
     else:
@@ -344,9 +351,19 @@ def SetTarget(target, arch=None):
             if arch not in 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:
-            arch = 'arm'
+            # If compiling on Android, default to same architecture.  Otherwise, arm.
+            if host == 'android':
+                arch = host_arch
+            else:
+                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
         global ANDROID_ABI
@@ -356,14 +373,23 @@ def SetTarget(target, arch=None):
         elif arch == 'arm':
             ANDROID_ABI = 'armeabi'
             TOOLCHAIN_PREFIX = 'arm-linux-androideabi-'
-        elif arch == 'x86':
-            ANDROID_ABI = 'x86'
-            TOOLCHAIN_PREFIX = 'i686-linux-android-'
+        elif arch == 'aarch64':
+            ANDROID_ABI = 'arm64-v8a'
+            TOOLCHAIN_PREFIX = 'aarch64-linux-android-'
         elif arch == 'mips':
             ANDROID_ABI = 'mips'
             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:
-            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':
         if arch is not None:
@@ -413,13 +439,13 @@ def CrossCompiling():
     return GetTarget() != GetHost()
 
 def GetCC():
-    if TARGET == 'darwin' or TARGET == 'freebsd':
+    if TARGET in ('darwin', 'freebsd', 'android'):
         return os.environ.get('CC', TOOLCHAIN_PREFIX + 'clang')
     else:
         return os.environ.get('CC', TOOLCHAIN_PREFIX + 'gcc')
 
 def GetCXX():
-    if TARGET == 'darwin' or TARGET == 'freebsd':
+    if TARGET in ('darwin', 'freebsd', 'android'):
         return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'clang++')
     else:
         return os.environ.get('CXX', TOOLCHAIN_PREFIX + 'g++')
@@ -2339,6 +2365,16 @@ def SdkLocateAndroid():
     if GetTarget() != 'android':
         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.
     if 'NDK_ROOT' not in os.environ:
         exit('NDK_ROOT must be set when compiling for Android!')
@@ -2355,18 +2391,20 @@ def SdkLocateAndroid():
     if arch == 'armv7a' or arch == 'arm':
         arch = 'arm'
         toolchain = 'arm-linux-androideabi-' + gcc_ver
-    elif arch == 'x86':
-        toolchain = 'x86-' + gcc_ver
+    elif arch == 'aarch64':
+        toolchain = 'aarch64-linux-android-' + gcc_ver
     elif arch == 'mips':
         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)
 
-    # Allow ANDROID_ABI to be used in makepanda.py.
-    abi = ANDROID_ABI
-    SDK["ANDROID_ABI"] = abi
-
     # 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'))
 
     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("Host OS: %s" % GetHost())
         print("Host arch: %s" % GetHostArch())
+
+    target = GetTarget()
+    if target != 'android':
         print("Target OS: %s" % GetTarget())
+    else:
+        print("Target OS: %s (API level %d)" % (GetTarget(), ANDROID_API))
     print("Target arch: %s" % GetTargetArch())
 
     # Set to English so we can safely parse the result of gcc commands.
@@ -2732,7 +2775,7 @@ def SetupBuildEnvironment(compiler):
                 print("  " + dir)
 
     # 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.
         prebuilt_dir = os.path.join(SDK['ANDROID_TOOLCHAIN'], 'prebuilt')
         if not os.path.isdir(prebuilt_dir):