diff --git a/makepanda/makepackage.py b/makepanda/makepackage.py index 85e96e3491..c11651283a 100755 --- a/makepanda/makepackage.py +++ b/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") diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 6e56cfccf3..792bf5ebfc 100755 --- a/makepanda/makepanda.py +++ b/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: diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 8790538395..6babeb7fd8 100644 --- a/makepanda/makepandacore.py +++ b/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 - # Determine the NDK installation directory. - if 'NDK_ROOT' not in os.environ: - exit('NDK_ROOT must be set when compiling for Android!') + 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)) - 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)) + # Determine the NDK installation directory. + 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') + + 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)"):