Răsfoiți Sursa

makepanda: support cross-compiling for Android again

rdb 7 ani în urmă
părinte
comite
c0b973b789
3 a modificat fișierele cu 74 adăugiri și 13 ștergeri
  1. 13 2
      makepanda/makepackage.py
  2. 4 1
      makepanda/makepanda.py
  3. 57 10
      makepanda/makepandacore.py

+ 13 - 2
makepanda/makepackage.py

@@ -867,6 +867,11 @@ def MakeInstallerAndroid(version, **kwargs):
             line = line.strip()
             if not line:
                 continue
+
+            if ' ' in line:
+                line = line.split(' ', 1)[0]
+
+            # Change .so.1.2 suffix to .so, as needed for loading in .apk
             if '.so.' in line:
                 dep = line.rpartition('.so.')[0] + '.so'
                 oscmd("patchelf --replace-needed %s %s %s" % (line, dep, target), True)
@@ -960,7 +965,7 @@ def MakeInstallerAndroid(version, **kwargs):
     aapt_cmd += " -F %s" % (apk_unaligned)
     aapt_cmd += " -M apkroot/AndroidManifest.xml"
     aapt_cmd += " -A apkroot/assets -S apkroot/res"
-    aapt_cmd += " -I $PREFIX/share/aapt/android.jar"
+    aapt_cmd += " -I %s" % (SDK["ANDROID_JAR"])
     oscmd(aapt_cmd)
 
     # And add all the libraries to it.
@@ -974,7 +979,13 @@ def MakeInstallerAndroid(version, **kwargs):
     oscmd("zipalign -v -p 4 %s %s" % (apk_unaligned, apk_unsigned))
 
     # Finally, sign it using a debug key.  This is generated if it doesn't exist.
-    oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned))
+    if GetHost() == 'android':
+        # Termux version of apksigner automatically generates a debug key.
+        oscmd("apksigner debug.ks %s panda3d.apk" % (apk_unsigned))
+    else:
+        if not os.path.isfile('debug.ks'):
+            oscmd("keytool -genkey -noprompt -dname 'CN=Panda3D,O=Panda3D,C=US' -keystore debug.ks -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 1000")
+        oscmd("apksigner sign --ks debug.ks --ks-pass pass:android --min-sdk-version %s --out panda3d.apk %s" % (SDK["ANDROID_API"], apk_unsigned))
 
     # Clean up.
     oscmd("rm -rf apkroot")

+ 4 - 1
makepanda/makepanda.py

@@ -2043,7 +2043,10 @@ def CompileRsrc(target, src, opts):
 
 def CompileJava(target, src, opts):
     """Compiles a .java file into a .class file."""
-    cmd = "ecj "
+    if GetHost() == 'android':
+        cmd = "ecj "
+    else:
+        cmd = "javac -bootclasspath " + BracketNameWithQuotes(SDK["ANDROID_JAR"]) + " "
 
     optlevel = GetOptimizeOption(opts)
     if optlevel >= 4:

+ 57 - 10
makepanda/makepandacore.py

@@ -2463,22 +2463,40 @@ def SdkLocateAndroid():
     SDK["ANDROID_TRIPLE"] = ANDROID_TRIPLE
 
     if GetHost() == 'android':
+        # Assume we're compiling from termux.
+        prefix = os.environ.get("PREFIX", "/data/data/com.termux/files/usr")
+        SDK["ANDROID_JAR"] = prefix + "/share/aapt/android.jar"
         return
 
+    sdk_root = os.environ.get('ANDROID_HOME')
+    if not sdk_root or not os.path.isdir(sdk_root):
+        sdk_root = os.environ.get('ANDROID_SDK_ROOT')
+        if not sdk_root:
+            exit('ANDROID_SDK_ROOT must be set when compiling for Android!')
+        elif not os.path.isdir(sdk_root):
+            exit('Cannot find %s.  Please install Android SDK and set ANDROID_SDK_ROOT or ANDROID_HOME.' % (sdk_root))
+
     # Determine the NDK installation directory.
-    if 'NDK_ROOT' not in os.environ:
-        exit('NDK_ROOT must be set when compiling for Android!')
+    if os.environ.get('NDK_ROOT') or os.environ.get('ANDROID_NDK_ROOT'):
+        # We have an explicit setting from an environment variable.
+        ndk_root = os.environ.get('ANDROID_NDK_ROOT')
+        if not ndk_root or not os.path.isdir(ndk_root):
+            ndk_root = os.environ.get('NDK_ROOT')
+            if not ndk_root or not os.path.isdir(ndk_root):
+                exit("Cannot find %s.  Please install Android NDK and set ANDROID_NDK_ROOT." % (ndk_root))
+    else:
+        # Often, it's installed in the ndk-bundle subdirectory of the SDK.
+        ndk_root = os.path.join(sdk_root, 'ndk-bundle')
 
-    ndk_root = os.environ["NDK_ROOT"]
-    if not os.path.isdir(ndk_root):
-        exit("Cannot find %s.  Please install Android NDK and set NDK_ROOT." % (ndk_root))
+        if not os.path.isdir(os.path.join(ndk_root, 'toolchains')):
+            exit('Cannot find the Android NDK.  Install it via the SDK manager or set the ANDROID_NDK_ROOT variable if you have installed it in a different location.')
 
     SDK["ANDROID_NDK"] = ndk_root
 
     # Determine the toolchain location.
     prebuilt_dir = os.path.join(ndk_root, 'toolchains', 'llvm', 'prebuilt')
     if not os.path.isdir(prebuilt_dir):
-        exit('Not found: %s' % (prebuilt_dir))
+        exit('Not found: %s (is the Android NDK installed?)' % (prebuilt_dir))
 
     host_tag = GetHost() + '-x86'
     if host_64:
@@ -2527,7 +2545,24 @@ def SdkLocateAndroid():
     # STL that ships with Android.
     support = os.path.join(ndk_root, 'sources', 'android', 'support', 'include')
     IncDirectory("ALWAYS", support.replace('\\', '/'))
-    LibName("ALWAYS", "-landroid_support")
+    if api < 21:
+        LibName("ALWAYS", "-landroid_support")
+
+    # Determine the location of android.jar.
+    SDK["ANDROID_JAR"] = os.path.join(sdk_root, 'platforms', 'android-%s' % (api), 'android.jar')
+
+    # Which build tools versions do we have?  Pick the latest.
+    versions = []
+    for version in os.listdir(os.path.join(sdk_root, "build-tools")):
+        match = re.match('([0-9]+)\\.([0-9]+)\\.([0-9]+)', version)
+        if match:
+            version_tuple = int(match.group(1)), int(match.group(2)), int(match.group(3))
+            versions.append(version_tuple)
+
+    versions.sort()
+    if versions:
+        version = versions[-1]
+        SDK["ANDROID_BUILD_TOOLS"] = os.path.join(sdk_root, "build-tools", "{0}.{1}.{2}".format(*version))
 
 ########################################################################
 ##
@@ -2793,6 +2828,9 @@ def SetupBuildEnvironment(compiler):
     if GetTarget() == 'android' and GetHost() != 'android':
         AddToPathEnv("PATH", os.path.join(SDK["ANDROID_TOOLCHAIN"], "bin"))
 
+        if "ANDROID_BUILD_TOOLS" in SDK:
+            AddToPathEnv("PATH", SDK["ANDROID_BUILD_TOOLS"])
+
     if compiler == "MSVC":
         # Add the visual studio tools to PATH et al.
         SetupVisualStudioEnviron()
@@ -2845,7 +2883,12 @@ def SetupBuildEnvironment(compiler):
             SYS_LIB_DIRS += [SDK.get("SYSROOT", "") + "/usr/lib"]
 
         # Now extract the preprocessor's include directories.
-        cmd = GetCXX() + sysroot_flag + " -x c++ -v -E /dev/null"
+        cmd = GetCXX() + " -x c++ -v -E " + os.devnull
+        if "ANDROID_NDK" in SDK:
+            cmd += " --sysroot=%s/sysroot" % (SDK["ANDROID_NDK"].replace('\\', '/'))
+        else:
+            cmd += sysroot_flag
+
         null = open(os.devnull, 'w')
         handle = subprocess.Popen(cmd, stdout=null, stderr=subprocess.PIPE, shell=True)
         scanning = False
@@ -2858,8 +2901,12 @@ def SetupBuildEnvironment(compiler):
                     scanning = True
                 continue
 
-            if not line.startswith(' /'):
-                continue
+            if sys.platform == "win32":
+                if not line.startswith(' '):
+                    continue
+            else:
+                if not line.startswith(' /'):
+                    continue
 
             line = line.strip()
             if line.endswith(" (framework directory)"):