192 lines
6.8 KiB
Python
192 lines
6.8 KiB
Python
import os.path
|
|
import platform
|
|
import shutil
|
|
from typing import Union
|
|
|
|
def with_ccache(command: str) -> str:
|
|
ccache = shutil.which('ccache')
|
|
if ccache is None:
|
|
return command
|
|
else:
|
|
return f'{ccache} {command}'
|
|
|
|
android_abis = {
|
|
'armeabi-v7a': {
|
|
'arch': 'armv7a-linux-androideabi',
|
|
'ndk_arch': 'arm',
|
|
'cflags': '-fpic -mfpu=neon -mfloat-abi=softfp',
|
|
},
|
|
|
|
'arm64-v8a': {
|
|
'arch': 'aarch64-linux-android',
|
|
'ndk_arch': 'arm64',
|
|
'cflags': '-fpic',
|
|
},
|
|
|
|
'x86': {
|
|
'arch': 'i686-linux-android',
|
|
'ndk_arch': 'x86',
|
|
'cflags': '-fPIC -march=i686 -mtune=intel -mssse3 -mfpmath=sse -m32',
|
|
},
|
|
|
|
'x86_64': {
|
|
'arch': 'x86_64-linux-android',
|
|
'ndk_arch': 'x86_64',
|
|
'cflags': '-fPIC -m64',
|
|
},
|
|
}
|
|
|
|
# https://developer.android.com/ndk/guides/other_build_systems
|
|
def build_arch() :
|
|
platforms = {
|
|
'Linux': 'linux-x86_64',
|
|
'Windows': 'windows-x86_64',
|
|
'Darwin': 'darwin-x86_64' # Despite the x86_64 tag in the Darwin name, those are fat binaries that include M1 support.
|
|
}
|
|
|
|
return platforms.get(platform.system())
|
|
|
|
|
|
class AndroidNdkToolchain:
|
|
def __init__(self, top_path: str, lib_path: str,
|
|
tarball_path: str, src_path: str,
|
|
ndk_path: str, android_abi: str,
|
|
use_cxx):
|
|
# select the NDK target
|
|
abi_info = android_abis[android_abi]
|
|
host_triplet = abi_info['arch']
|
|
|
|
arch_path = os.path.join(lib_path, host_triplet)
|
|
|
|
self.tarball_path = tarball_path
|
|
self.src_path = src_path
|
|
self.build_path = os.path.join(arch_path, 'build')
|
|
|
|
ndk_arch = abi_info['ndk_arch']
|
|
android_api_level = '24'
|
|
|
|
install_prefix = os.path.join(arch_path, 'root')
|
|
|
|
self.host_triplet = host_triplet
|
|
self.install_prefix = install_prefix
|
|
|
|
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch())
|
|
llvm_triple = host_triplet + android_api_level
|
|
|
|
common_flags = '-Os -g'
|
|
common_flags += ' ' + abi_info['cflags']
|
|
|
|
llvm_bin = os.path.join(llvm_path, 'bin')
|
|
self.cc = with_ccache(os.path.join(llvm_bin, 'clang'))
|
|
self.cxx = with_ccache(os.path.join(llvm_bin, 'clang++'))
|
|
common_flags += ' -target ' + llvm_triple
|
|
|
|
common_flags += ' -fvisibility=hidden -fdata-sections -ffunction-sections'
|
|
|
|
self.ar = os.path.join(llvm_bin, 'llvm-ar')
|
|
self.arflags = 'rcs'
|
|
self.ranlib = os.path.join(llvm_bin, 'llvm-ranlib')
|
|
self.nm = os.path.join(llvm_bin, 'llvm-nm')
|
|
self.strip = os.path.join(llvm_bin, 'llvm-strip')
|
|
|
|
self.cflags = common_flags
|
|
self.cxxflags = common_flags
|
|
self.cppflags = ' -isystem ' + os.path.join(install_prefix, 'include')
|
|
self.ldflags = ' -L' + os.path.join(install_prefix, 'lib') + \
|
|
' -Wl,--exclude-libs=ALL' + \
|
|
' ' + common_flags
|
|
self.ldflags = common_flags
|
|
self.libs = ''
|
|
|
|
self.is_arm = ndk_arch == 'arm'
|
|
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
|
self.is_aarch64 = ndk_arch == 'arm64'
|
|
self.is_windows = False
|
|
self.is_android = True
|
|
self.is_darwin = False
|
|
|
|
libstdcxx_flags = ''
|
|
libstdcxx_cxxflags = ''
|
|
libstdcxx_ldflags = ''
|
|
libstdcxx_libs = '-static-libstdc++'
|
|
|
|
if self.is_armv7:
|
|
# On 32 bit ARM, clang generates no ".eh_frame" section;
|
|
# instead, the LLVM unwinder library is used for unwinding
|
|
# the stack after a C++ exception was thrown
|
|
libstdcxx_libs += ' -lunwind'
|
|
|
|
if use_cxx:
|
|
self.cxxflags += ' ' + libstdcxx_cxxflags
|
|
self.ldflags += ' ' + libstdcxx_ldflags
|
|
self.libs += ' ' + libstdcxx_libs
|
|
|
|
self.env = dict(os.environ)
|
|
|
|
# redirect pkg-config to use our root directory instead of the
|
|
# default one on the build host
|
|
bin_dir = os.path.join(install_prefix, 'bin')
|
|
os.makedirs(bin_dir, exist_ok=True)
|
|
self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
|
|
os.path.join(bin_dir, 'pkg-config'))
|
|
self.env['PKG_CONFIG'] = self.pkg_config
|
|
|
|
class MingwToolchain:
|
|
def __init__(self, top_path: str,
|
|
toolchain_path, host_triplet, x64: bool,
|
|
tarball_path, src_path, build_path, install_prefix):
|
|
self.host_triplet = host_triplet
|
|
self.tarball_path = tarball_path
|
|
self.src_path = src_path
|
|
self.build_path = build_path
|
|
self.install_prefix = install_prefix
|
|
|
|
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
|
self.cc = with_ccache(os.path.join(toolchain_bin, host_triplet + '-gcc'))
|
|
self.cxx = with_ccache(os.path.join(toolchain_bin, host_triplet + '-g++'))
|
|
self.ar = os.path.join(toolchain_bin, host_triplet + '-ar')
|
|
self.arflags = 'rcs'
|
|
self.ranlib = os.path.join(toolchain_bin, host_triplet + '-ranlib')
|
|
self.nm = os.path.join(toolchain_bin, host_triplet + '-nm')
|
|
self.strip = os.path.join(toolchain_bin, host_triplet + '-strip')
|
|
self.windres = os.path.join(toolchain_bin, host_triplet + '-windres')
|
|
|
|
common_flags = '-O2 -g'
|
|
|
|
if not x64:
|
|
# enable SSE support which is required for LAME
|
|
common_flags += ' -march=pentium3'
|
|
|
|
self.cflags = common_flags
|
|
self.cxxflags = common_flags
|
|
self.cppflags = '-isystem ' + os.path.join(install_prefix, 'include') + \
|
|
' -DWINVER=0x0600 -D_WIN32_WINNT=0x0600'
|
|
self.ldflags = '-L' + os.path.join(install_prefix, 'lib') + \
|
|
' -static-libstdc++ -static-libgcc'
|
|
self.libs = ''
|
|
|
|
# Explicitly disable _FORTIFY_SOURCE because it is broken with
|
|
# mingw. This prevents some libraries such as libFLAC to
|
|
# enable it.
|
|
self.cppflags += ' -D_FORTIFY_SOURCE=0'
|
|
|
|
self.is_arm = host_triplet.startswith('arm')
|
|
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
|
self.is_aarch64 = host_triplet == 'aarch64'
|
|
self.is_windows = 'mingw32' in host_triplet
|
|
self.is_android = False
|
|
self.is_darwin = False
|
|
|
|
self.env = dict(os.environ)
|
|
|
|
# redirect pkg-config to use our root directory instead of the
|
|
# default one on the build host
|
|
import shutil
|
|
bin_dir = os.path.join(install_prefix, 'bin')
|
|
os.makedirs(bin_dir, exist_ok=True)
|
|
self.pkg_config = shutil.copy(os.path.join(top_path, 'build', 'pkg-config.sh'),
|
|
os.path.join(bin_dir, 'pkg-config'))
|
|
self.env['PKG_CONFIG'] = self.pkg_config
|
|
|
|
AnyToolchain = Union[AndroidNdkToolchain, MingwToolchain]
|