diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index b00c947208..2f21483e78 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -821,9 +821,6 @@ if (COMPILER=="GCC"): SmartPkgEnable("FREETYPE", "freetype2", ("freetype"), ("freetype2", "freetype2/freetype/freetype.h")) SmartPkgEnable("HARFBUZZ", "harfbuzz", ("harfbuzz"), ("harfbuzz", "harfbuzz/hb-ft.h")) SmartPkgEnable("GL", "gl", ("GL"), ("GL/gl.h"), framework = "OpenGL") - SmartPkgEnable("GLES", "glesv1_cm", ("GLESv1_CM"), ("GLES/gl.h"), framework = "OpenGLES") - SmartPkgEnable("GLES2", "glesv2", ("GLESv2"), ("GLES2/gl2.h")) #framework = "OpenGLES"? - SmartPkgEnable("EGL", "egl", ("EGL"), ("EGL/egl.h")) SmartPkgEnable("NVIDIACG", "", ("Cg"), "Cg/cg.h", framework = "Cg") SmartPkgEnable("ODE", "", ("ode"), "ode/ode.h", tool = "ode-config") SmartPkgEnable("OPENAL", "openal", ("openal"), "AL/al.h", framework = "OpenAL") @@ -837,6 +834,12 @@ if (COMPILER=="GCC"): SmartPkgEnable("JPEG", "", ("jpeg"), "jpeglib.h") SmartPkgEnable("PNG", "libpng", ("png"), "png.h", tool = "libpng-config") + # On Android, these are system libraries. + if GetHost() != "android": + SmartPkgEnable("GLES", "glesv1_cm", (), ("GLES/gl.h"), framework = "OpenGLES") + SmartPkgEnable("GLES2", "glesv2", (), ("GLES2/gl2.h")) #framework = "OpenGLES"? + SmartPkgEnable("EGL", "egl", (), ("EGL/egl.h")) + if not PkgSkip("FFMPEG"): if GetTarget() == "darwin": LibName("FFMPEG", "-Wl,-read_only_relocs,suppress") @@ -1251,7 +1254,13 @@ def CompileCxx(obj,src,opts): cmd += " -arch %s" % arch if "SYSROOT" in SDK: - cmd += ' --sysroot=%s -no-canonical-prefixes' % (SDK["SYSROOT"]) + if GetTarget() != "android": + cmd += ' --sysroot=%s' % (SDK["SYSROOT"]) + else: + ndk_dir = SDK["ANDROID_NDK"].replace('\\', '/') + cmd += ' -isystem %s/sysroot/usr/include' % (ndk_dir) + cmd += ' -isystem %s/sysroot/usr/include/%s' % (ndk_dir, SDK["ANDROID_TRIPLE"]) + cmd += ' -no-canonical-prefixes' # Android-specific flags. arch = GetTargetArch() @@ -1261,33 +1270,38 @@ def CompileCxx(obj,src,opts): # 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/libs/%s/include' % (SDK["ANDROID_STL"], SDK["ANDROID_ABI"]) + if "ANDROID_GCC_TOOLCHAIN" in SDK: + cmd += ' -gcc-toolchain ' + SDK["ANDROID_GCC_TOOLCHAIN"].replace('\\', '/') 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__' - cmd += ' -fstack-protector -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16' + cmd += ' -target armv7-none-linux-androideabi' + cmd += ' -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16' + cmd += ' -fno-integrated-as' elif arch == 'arm': - cmd += ' -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__' - cmd += ' -fstack-protector -march=armv5te -mtune=xscale -msoft-float' + cmd += ' -target armv5te-none-linux-androideabi' + cmd += ' -march=armv5te -mtune=xscale -msoft-float' + cmd += ' -fno-integrated-as' + elif arch == 'aarch64': + cmd += ' -target aarch64-none-linux-android' elif arch == 'mips': - cmd += ' -finline-functions -fmessage-length=0' - cmd += ' -fno-inline-functions-called-once -fgcse-after-reload' - cmd += ' -frerun-cse-after-loop -frename-registers' + cmd += ' -target mipsel-none-linux-android' + cmd += ' -mips32' + elif arch == 'mips64': + cmd += ' -target mips64el-none-linux-android' + cmd += ' -fintegrated-as' + elif arch == 'x86': + cmd += ' -target i686-none-linux-android' + cmd += ' -mstackrealign' + elif arch == 'x86_64': + cmd += ' -target x86_64-none-linux-android' cmd += " -Wa,--noexecstack" - # Now add specific release/debug flags. - if optlevel >= 3: - cmd += " -fomit-frame-pointer" - if arch.startswith('arm'): - cmd += ' -finline-limit=64 -mthumb' - elif arch == 'mips': - cmd += ' -funswitch-loops -finline-limit=300' - else: - cmd += ' -fno-omit-frame-pointer' - if arch.startswith('arm'): + # Do we want thumb or arm instructions? + if arch.startswith('arm'): + if optlevel >= 3: + cmd += ' -mthumb' + else: cmd += ' -marm' # Enable SIMD instructions if requested @@ -1745,9 +1759,26 @@ def CompileLink(dll, obj, opts): cmd += " -arch %s" % arch elif GetTarget() == 'android': + arch = GetTargetArch() + if "ANDROID_GCC_TOOLCHAIN" in SDK: + cmd += ' -gcc-toolchain ' + SDK["ANDROID_GCC_TOOLCHAIN"].replace('\\', '/') cmd += " -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now" - if GetTargetArch() == 'armv7a': + if arch == 'armv7a': + cmd += ' -target armv7-none-linux-androideabi' cmd += " -march=armv7-a -Wl,--fix-cortex-a8" + elif arch == 'arm': + cmd += ' -target armv5te-none-linux-androideabi' + elif arch == 'aarch64': + cmd += ' -target aarch64-none-linux-android' + elif arch == 'mips': + cmd += ' -target mipsel-none-linux-android' + cmd += ' -mips32' + elif arch == 'mips64': + cmd += ' -target mips64el-none-linux-android' + elif arch == 'x86': + cmd += ' -target i686-none-linux-android' + elif arch == 'x86_64': + cmd += ' -target x86_64-none-linux-android' cmd += ' -lc -lm' else: cmd += " -pthread" diff --git a/makepanda/makepandacore.py b/makepanda/makepandacore.py index 75211d3979..bc0cdc7549 100644 --- a/makepanda/makepandacore.py +++ b/makepanda/makepandacore.py @@ -37,7 +37,8 @@ TARGET_ARCH = None HAS_TARGET_ARCH = False TOOLCHAIN_PREFIX = "" ANDROID_ABI = None -ANDROID_API = 14 +ANDROID_TRIPLE = None +ANDROID_API = None SYS_LIB_DIRS = [] SYS_INC_DIRS = [] DEBUG_DEPENDENCIES = False @@ -359,40 +360,48 @@ def SetTarget(target, arch=None): if host == 'android': arch = host_arch else: - arch = 'arm' + arch = 'armv7a' # Did we specify an API level? + global ANDROID_API target, _, api = target.partition('-') if api: - global ANDROID_API ANDROID_API = int(api) + elif arch in ('mips64', 'aarch64', 'x86_64'): + # 64-bit platforms were introduced in Android 21. + ANDROID_API = 21 + else: + # Default to the lowest API level supported by NDK r16. + ANDROID_API = 14 # Determine the prefix for our gcc tools, eg. arm-linux-androideabi-gcc - global ANDROID_ABI + global ANDROID_ABI, ANDROID_TRIPLE if arch == 'armv7a': ANDROID_ABI = 'armeabi-v7a' - TOOLCHAIN_PREFIX = 'arm-linux-androideabi-' + ANDROID_TRIPLE = 'arm-linux-androideabi' elif arch == 'arm': ANDROID_ABI = 'armeabi' - TOOLCHAIN_PREFIX = 'arm-linux-androideabi-' + ANDROID_TRIPLE = 'arm-linux-androideabi' elif arch == 'aarch64': ANDROID_ABI = 'arm64-v8a' - TOOLCHAIN_PREFIX = 'aarch64-linux-android-' + ANDROID_TRIPLE = 'aarch64-linux-android' elif arch == 'mips': ANDROID_ABI = 'mips' - TOOLCHAIN_PREFIX = 'mipsel-linux-android-' + ANDROID_TRIPLE = 'mipsel-linux-android' elif arch == 'mips64': ANDROID_ABI = 'mips64' - TOOLCHAIN_PREFIX = 'mips64el-linux-android-' + ANDROID_TRIPLE = 'mips64el-linux-android' elif arch == 'x86': ANDROID_ABI = 'x86' - TOOLCHAIN_PREFIX = 'i686-linux-android-' + ANDROID_TRIPLE = 'i686-linux-android' elif arch == 'x86_64': ANDROID_ABI = 'x86_64' - TOOLCHAIN_PREFIX = 'x86_64-linux-android-' + ANDROID_TRIPLE = 'x86_64-linux-android' else: exit('Android architecture must be arm, armv7a, aarch64, mips, mips64, x86 or x86_64') + TOOLCHAIN_PREFIX = ANDROID_TRIPLE + '-' + elif target == 'linux': if arch is not None: TOOLCHAIN_PREFIX = '%s-linux-gnu-' % arch @@ -2359,6 +2368,8 @@ def SdkLocateAndroid(): """This actually locates the Android NDK, not the Android SDK. NDK_ROOT must be set to its root directory.""" + global TOOLCHAIN_PREFIX + if GetTarget() != 'android': return @@ -2368,6 +2379,7 @@ def SdkLocateAndroid(): abi = ANDROID_ABI SDK["ANDROID_ABI"] = abi + SDK["ANDROID_TRIPLE"] = ANDROID_TRIPLE if GetHost() == 'android': return @@ -2383,36 +2395,58 @@ def SdkLocateAndroid(): SDK["ANDROID_NDK"] = ndk_root # Determine the toolchain location. - gcc_ver = '4.8' + prebuilt_dir = os.path.join(ndk_root, 'toolchains', 'llvm', 'prebuilt') + if not os.path.isdir(prebuilt_dir): + exit('Not found: %s' % (prebuilt_dir)) + + host_tag = GetHost() + '-x86' + if host_64: + host_tag += '_64' + elif host_tag == 'windows-x86': + host_tag = 'windows' + + prebuilt_dir = os.path.join(prebuilt_dir, host_tag) + if host_tag == 'windows-x86_64' and not os.path.isdir(prebuilt_dir): + # Try the 32-bits toolchain instead. + host_tag = 'windows' + prebuilt_dir = os.path.join(prebuilt_dir, host_tag) + + SDK["ANDROID_TOOLCHAIN"] = prebuilt_dir + + # And locate the GCC toolchain, which is needed for some tools (eg. as/ld) arch = GetTargetArch() - if arch == 'armv7a' or arch == 'arm': - arch = 'arm' - toolchain = 'arm-linux-androideabi-' + 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) + for opt in (TOOLCHAIN_PREFIX + '4.9', arch + '-4.9', TOOLCHAIN_PREFIX + '4.8', arch + '-4.8'): + if os.path.isdir(os.path.join(ndk_root, 'toolchains', opt)): + SDK["ANDROID_GCC_TOOLCHAIN"] = os.path.join(ndk_root, 'toolchains', opt, 'prebuilt', host_tag) + break + + # The prebuilt binaries have no toolchain prefix. + TOOLCHAIN_PREFIX = '' # Determine the sysroot directory. - SDK["SYSROOT"] = os.path.join(ndk_root, 'platforms', 'android-%s' % (api), 'arch-%s' % (arch)) + if arch == 'armv7a': + arch_dir = 'arch-arm' + elif arch == 'aarch64': + arch_dir = 'arch-arm64' + else: + arch_dir = 'arch-' + arch + SDK["SYSROOT"] = os.path.join(ndk_root, 'platforms', 'android-%s' % (api), arch_dir).replace('\\', '/') #IncDirectory("ALWAYS", os.path.join(SDK["SYSROOT"], 'usr', 'include')) - stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'gnu-libstdc++', gcc_ver) - SDK["ANDROID_STL"] = stdlibc + # Starting with NDK r16, libc++ is the recommended STL to use. + stdlibc = os.path.join(ndk_root, 'sources', 'cxx-stl', 'llvm-libc++') + IncDirectory("ALWAYS", os.path.join(stdlibc, 'include').replace('\\', '/')) + LibDirectory("ALWAYS", os.path.join(stdlibc, 'libs', abi).replace('\\', '/')) - #IncDirectory("ALWAYS", os.path.join(stdlibc, 'include')) - #IncDirectory("ALWAYS", os.path.join(stdlibc, 'libs', abi, 'include')) + stl_lib = os.path.join(stdlibc, 'libs', abi, 'libc++_shared.so') + LibName("ALWAYS", stl_lib.replace('\\', '/')) + CopyFile(os.path.join(GetOutputDir(), 'lib', 'libc++_shared.so'), stl_lib) - stl_lib = os.path.join(stdlibc, 'libs', abi, 'libgnustl_shared.so') - LibName("ALWAYS", stl_lib) - CopyFile(os.path.join(GetOutputDir(), 'libs', abi, 'libgnustl_shared.so'), stl_lib) + # The Android support library polyfills C++ features not available in the + # STL that ships with Android. + support = os.path.join(ndk_root, 'sources', 'android', 'support', 'include') + IncDirectory("ALWAYS", support.replace('\\', '/')) + LibName("ALWAYS", "-landroid_support") ######################################################################## ## @@ -2675,6 +2709,10 @@ def SetupBuildEnvironment(compiler): os.environ["LC_ALL"] = "en_US.UTF-8" os.environ["LANGUAGE"] = "en" + # In the case of Android, we have to put the toolchain on the PATH in order to use it. + if GetTarget() == 'android' and GetHost() != 'android': + AddToPathEnv("PATH", os.path.join(SDK["ANDROID_TOOLCHAIN"], "bin")) + if compiler == "MSVC": # Add the visual studio tools to PATH et al. SetupVisualStudioEnviron() @@ -2709,11 +2747,15 @@ def SetupBuildEnvironment(compiler): continue line = line[12:].strip() - for libdir in line.split(':'): - libdir = os.path.normpath(libdir) + libdirs = line.split(':') + while libdirs: + libdir = os.path.normpath(libdirs.pop(0)) if os.path.isdir(libdir): if libdir not in SYS_LIB_DIRS: SYS_LIB_DIRS.append(libdir) + elif len(libdir) == 1: + # Oops, is this a drive letter? Prepend it to the next. + libdirs[0] = libdir + ':' + libdirs[0] elif GetVerbose(): print("Ignoring non-existent library directory %s" % (libdir)) @@ -2771,33 +2813,6 @@ def SetupBuildEnvironment(compiler): for dir in SYS_INC_DIRS: print(" " + dir) - # In the case of Android, we have to put the toolchain on the PATH in order to use it. - 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): - exit('Not found: %s' % (prebuilt_dir)) - - host_tag = GetHost() + '-x86' - if host_64: - host_tag += '_64' - elif host_tag == 'windows-x86': - host_tag = 'windows' - - prebuilt_dir = os.path.join(prebuilt_dir, host_tag) - if host_64 and not os.path.isdir(prebuilt_dir): - # Try the 32-bits toolchain instead. - prebuilt_dir = os.path.join(prebuilt_dir, host_tag) - - if not os.path.isdir(prebuilt_dir): - if host_64: - exit('Not found: %s or %s' % (prebuilt_dir, host_tag)) - else: - exit('Not found: %s' % (prebuilt_dir)) - - # Then, add it to the PATH. - AddToPathEnv("PATH", os.path.join(prebuilt_dir, 'bin')) - # If we're cross-compiling, no point in putting our output dirs on the path. if CrossCompiling(): return