mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 07:48:37 -04:00
dist: Build multi-ABI distributions on Android
[skip ci]
This commit is contained in:
parent
834bc2298f
commit
1289d5bfb4
182
direct/src/dist/commands.py
vendored
182
direct/src/dist/commands.py
vendored
@ -216,6 +216,7 @@ class build_apps(setuptools.Command):
|
||||
def initialize_options(self):
|
||||
self.build_base = os.path.join(os.getcwd(), 'build')
|
||||
self.application_id = None
|
||||
self.android_abis = None
|
||||
self.android_debuggable = False
|
||||
self.android_version_code = 1
|
||||
self.android_min_sdk_version = 21
|
||||
@ -418,6 +419,18 @@ class build_apps(setuptools.Command):
|
||||
tmp.update(self.package_data_dirs)
|
||||
self.package_data_dirs = tmp
|
||||
|
||||
# Default to all supported ABIs (for the given Android version).
|
||||
if self.android_max_sdk_version and self.android_max_sdk_version < 21:
|
||||
if self.android_abis:
|
||||
for abi in self.android_abis:
|
||||
assert abi in ('mips64', 'x86_64', 'arm64-v8a'), \
|
||||
f'{abi} was not a valid Android ABI before Android 21!'
|
||||
else:
|
||||
self.android_abis = ['armeabi-v7a', 'x86']
|
||||
|
||||
elif not self.android_abis:
|
||||
self.android_abis = ['arm64-v8a', 'armeabi-v7a', 'x86_64', 'x86']
|
||||
|
||||
self.icon_objects = {}
|
||||
for app, iconpaths in self.icons.items():
|
||||
if not isinstance(iconpaths, list) and not isinstance(iconpaths, tuple):
|
||||
@ -434,7 +447,68 @@ class build_apps(setuptools.Command):
|
||||
self.announce('Building platforms: {0}'.format(','.join(self.platforms)), distutils.log.INFO)
|
||||
|
||||
for platform in self.platforms:
|
||||
self.build_runtimes(platform, True)
|
||||
# Create the build directory, or ensure it is empty.
|
||||
build_dir = os.path.join(self.build_base, platform)
|
||||
|
||||
if os.path.exists(build_dir):
|
||||
for entry in os.listdir(build_dir):
|
||||
path = os.path.join(build_dir, entry)
|
||||
if os.path.islink(path) or os.path.isfile(path):
|
||||
os.unlink(path)
|
||||
else:
|
||||
shutil.rmtree(path)
|
||||
else:
|
||||
os.makedirs(build_dir)
|
||||
|
||||
if platform == 'android':
|
||||
# Make a multi-arch build for Android.
|
||||
data_dir = os.path.join(build_dir, 'assets')
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
|
||||
for abi in self.android_abis:
|
||||
lib_dir = os.path.join(build_dir, 'lib', abi)
|
||||
os.makedirs(lib_dir, exist_ok=True)
|
||||
|
||||
suffix = None
|
||||
if abi == 'arm64-v8a':
|
||||
suffix = '_arm64'
|
||||
elif abi == 'armeabi-v7a':
|
||||
suffix = '_armv7a'
|
||||
elif abi == 'armeabi':
|
||||
suffix = '_arm'
|
||||
else: # e.g. x86, x86_64, mips, mips64
|
||||
suffix = '_' + abi.replace('-', '_')
|
||||
|
||||
self.build_binaries(lib_dir, platform + suffix)
|
||||
|
||||
# Write out the icons to the res directory.
|
||||
for appname, icon in self.icon_objects.items():
|
||||
if appname == '*' or (appname == self.macos_main_app and '*' not in self.icon_objects):
|
||||
# Conventional name for icon on Android.
|
||||
basename = 'ic_launcher.png'
|
||||
else:
|
||||
basename = f'ic_{appname}.png'
|
||||
|
||||
res_dir = os.path.join(build_dir, 'res')
|
||||
icon.writeSize(48, os.path.join(res_dir, 'mipmap-mdpi-v4', basename))
|
||||
icon.writeSize(72, os.path.join(res_dir, 'mipmap-hdpi-v4', basename))
|
||||
icon.writeSize(96, os.path.join(res_dir, 'mipmap-xhdpi-v4', basename))
|
||||
icon.writeSize(144, os.path.join(res_dir, 'mipmap-xxhdpi-v4', basename))
|
||||
|
||||
if icon.getLargestSize() >= 192:
|
||||
icon.writeSize(192, os.path.join(res_dir, 'mipmap-xxxhdpi-v4', basename))
|
||||
|
||||
self.build_data(data_dir, platform)
|
||||
|
||||
# Generate an AndroidManifest.xml
|
||||
self.generate_android_manifest(os.path.join(build_dir, 'AndroidManifest.xml'))
|
||||
else:
|
||||
self.build_binaries(build_dir, platform)
|
||||
self.build_data(build_dir, platform)
|
||||
|
||||
# Bundle into an .app on macOS
|
||||
if self.macos_main_app and 'macosx' in platform:
|
||||
self.bundle_macos_app(build_dir)
|
||||
|
||||
def download_wheels(self, platform):
|
||||
""" Downloads wheels for the given platform using pip. This includes panda3d
|
||||
@ -637,15 +711,10 @@ class build_apps(setuptools.Command):
|
||||
with open(path, 'wb') as fh:
|
||||
tree.write(fh, encoding='utf-8', xml_declaration=True)
|
||||
|
||||
def build_runtimes(self, platform, use_wheels):
|
||||
""" Builds the distributions for the given platform. """
|
||||
|
||||
builddir = os.path.join(self.build_base, platform)
|
||||
|
||||
if os.path.exists(builddir):
|
||||
shutil.rmtree(builddir)
|
||||
os.makedirs(builddir)
|
||||
def build_binaries(self, binary_dir, platform):
|
||||
""" Builds the binary data for the given platform. """
|
||||
|
||||
use_wheels = True
|
||||
path = sys.path[:]
|
||||
p3dwhl = None
|
||||
wheelpaths = []
|
||||
@ -774,15 +843,14 @@ class build_apps(setuptools.Command):
|
||||
prcexport = '\n'.join(prcexport)
|
||||
if not self.embed_prc_data:
|
||||
prcdir = self.default_prc_dir.replace('<auto>', '')
|
||||
prcdir = os.path.join(builddir, prcdir)
|
||||
prcdir = os.path.join(binary_dir, prcdir)
|
||||
os.makedirs(prcdir)
|
||||
with open (os.path.join(prcdir, '00-panda3d.prc'), 'w') as f:
|
||||
with open(os.path.join(prcdir, '00-panda3d.prc'), 'w') as f:
|
||||
f.write(prcexport)
|
||||
|
||||
# Create runtimes
|
||||
freezer_extras = set()
|
||||
freezer_modules = set()
|
||||
freezer_modpaths = set()
|
||||
ext_suffixes = set()
|
||||
|
||||
def get_search_path_for(source_path):
|
||||
@ -815,7 +883,7 @@ class build_apps(setuptools.Command):
|
||||
|
||||
return search_path
|
||||
|
||||
def create_runtime(appname, mainscript, target_dir, use_console):
|
||||
def create_runtime(platform, appname, mainscript, use_console):
|
||||
freezer = FreezeTool.Freezer(
|
||||
platform=platform,
|
||||
path=path,
|
||||
@ -872,7 +940,7 @@ class build_apps(setuptools.Command):
|
||||
if not self.log_filename or '%' not in self.log_filename:
|
||||
use_strftime = False
|
||||
|
||||
target_path = os.path.join(target_dir, target_name)
|
||||
target_path = os.path.join(binary_dir, target_name)
|
||||
freezer.generateRuntimeFromStub(target_path, stub_file, use_console, {
|
||||
'prc_data': prcexport if self.embed_prc_data else None,
|
||||
'default_prc_dir': self.default_prc_dir,
|
||||
@ -892,53 +960,23 @@ class build_apps(setuptools.Command):
|
||||
os.unlink(temp_file.name)
|
||||
|
||||
# Copy the dependencies.
|
||||
search_path = [target_dir]
|
||||
search_path = [binary_dir]
|
||||
if use_wheels:
|
||||
search_path.append(os.path.join(p3dwhlfn, 'panda3d'))
|
||||
search_path.append(os.path.join(p3dwhlfn, 'deploy_libs'))
|
||||
self.copy_dependencies(target_path, target_dir, search_path, stub_name)
|
||||
self.copy_dependencies(target_path, binary_dir, search_path, stub_name)
|
||||
|
||||
freezer_extras.update(freezer.extras)
|
||||
freezer_modules.update(freezer.getAllModuleNames())
|
||||
freezer_modpaths.update({
|
||||
mod[1].filename.to_os_specific()
|
||||
for mod in freezer.getModuleDefs() if mod[1].filename
|
||||
})
|
||||
for suffix in freezer.moduleSuffixes:
|
||||
if suffix[2] == imp.C_EXTENSION:
|
||||
ext_suffixes.add(suffix[0])
|
||||
|
||||
# Where should we copy the various file types to?
|
||||
lib_dir = builddir
|
||||
data_dir = builddir
|
||||
|
||||
if platform.startswith('android'):
|
||||
data_dir = os.path.join(data_dir, 'assets')
|
||||
if platform == 'android_arm64':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'arm64-v8a')
|
||||
elif platform == 'android_armv7a':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'armeabi-v7a')
|
||||
elif platform == 'android_arm':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'armeabi')
|
||||
elif platform == 'androidmips':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'mips')
|
||||
elif platform == 'android_mips64':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'mips64')
|
||||
elif platform == 'android_x86':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'x86')
|
||||
elif platform == 'android_x86_64':
|
||||
lib_dir = os.path.join(lib_dir, 'lib', 'x86_64')
|
||||
else:
|
||||
self.announce('Unrecognized Android architecture {}'.format(platform.split('_', 1)[-1]), distutils.log.ERROR)
|
||||
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
os.makedirs(lib_dir, exist_ok=True)
|
||||
|
||||
for appname, scriptname in self.gui_apps.items():
|
||||
create_runtime(appname, scriptname, lib_dir, False)
|
||||
create_runtime(platform, appname, scriptname, False)
|
||||
|
||||
for appname, scriptname in self.console_apps.items():
|
||||
create_runtime(appname, scriptname, lib_dir, True)
|
||||
create_runtime(platform, appname, scriptname, True)
|
||||
|
||||
# Copy extension modules
|
||||
whl_modules = []
|
||||
@ -974,7 +1012,7 @@ class build_apps(setuptools.Command):
|
||||
plugname = lib.split('.', 1)[0]
|
||||
if plugname in plugin_list:
|
||||
source_path = os.path.join(p3dwhlfn, lib)
|
||||
target_path = os.path.join(lib_dir, os.path.basename(lib))
|
||||
target_path = os.path.join(binary_dir, os.path.basename(lib))
|
||||
search_path = [os.path.dirname(source_path)]
|
||||
self.copy_with_dependencies(source_path, target_path, search_path)
|
||||
|
||||
@ -1021,7 +1059,7 @@ class build_apps(setuptools.Command):
|
||||
basename = 'libpy.' + basename
|
||||
|
||||
# If this is a dynamic library, search for dependencies.
|
||||
target_path = os.path.join(lib_dir, basename)
|
||||
target_path = os.path.join(binary_dir, basename)
|
||||
search_path = get_search_path_for(source_path)
|
||||
self.copy_with_dependencies(source_path, target_path, search_path)
|
||||
|
||||
@ -1032,19 +1070,19 @@ class build_apps(setuptools.Command):
|
||||
|
||||
if os.path.isdir(tcl_dir) and 'tkinter' in freezer_modules:
|
||||
self.announce('Copying Tcl files', distutils.log.INFO)
|
||||
os.makedirs(os.path.join(data_dir, 'tcl'))
|
||||
os.makedirs(os.path.join(binary_dir, 'tcl'))
|
||||
|
||||
for dir in os.listdir(tcl_dir):
|
||||
sub_dir = os.path.join(tcl_dir, dir)
|
||||
if os.path.isdir(sub_dir):
|
||||
target_dir = os.path.join(data_dir, 'tcl', dir)
|
||||
target_dir = os.path.join(binary_dir, 'tcl', dir)
|
||||
self.announce('copying {0} -> {1}'.format(sub_dir, target_dir))
|
||||
shutil.copytree(sub_dir, target_dir)
|
||||
|
||||
# Copy classes.dex on Android
|
||||
if use_wheels and platform.startswith('android'):
|
||||
self.copy(os.path.join(p3dwhlfn, 'deploy_libs', 'classes.dex'),
|
||||
os.path.join(builddir, 'classes.dex'))
|
||||
os.path.join(binary_dir, '..', '..', 'classes.dex'))
|
||||
|
||||
# Extract any other data files from dependency packages.
|
||||
for module, datadesc in self.package_data_dirs.items():
|
||||
@ -1082,15 +1120,18 @@ class build_apps(setuptools.Command):
|
||||
else:
|
||||
self.copy(source_path, target_path)
|
||||
|
||||
def build_data(self, data_dir, platform):
|
||||
""" Builds the data files for the given platform. """
|
||||
|
||||
# Copy Game Files
|
||||
self.announce('Copying game files for platform: {}'.format(platform), distutils.log.INFO)
|
||||
ignore_copy_list = [
|
||||
'**/__pycache__/**',
|
||||
'**/*.pyc',
|
||||
'**/*.py',
|
||||
'{}/**'.format(self.build_base),
|
||||
]
|
||||
ignore_copy_list += self.exclude_patterns
|
||||
ignore_copy_list += freezer_modpaths
|
||||
ignore_copy_list += self.extra_prc_files
|
||||
ignore_copy_list = [p3d.GlobPattern(p3d.Filename.from_os_specific(i).get_fullpath()) for i in ignore_copy_list]
|
||||
|
||||
@ -1191,31 +1232,6 @@ class build_apps(setuptools.Command):
|
||||
|
||||
copy_file(src, dst)
|
||||
|
||||
if 'android' in platform:
|
||||
# Generate an AndroidManifest.xml
|
||||
self.generate_android_manifest(os.path.join(builddir, 'AndroidManifest.xml'))
|
||||
|
||||
# Write out the icons to the res directory.
|
||||
for appname, icon in self.icon_objects.items():
|
||||
if appname == '*' or (appname == self.macos_main_app and '*' not in self.icon_objects):
|
||||
# Conventional name for icon on Android.
|
||||
basename = 'ic_launcher.png'
|
||||
else:
|
||||
basename = f'ic_{appname}.png'
|
||||
|
||||
res_dir = os.path.join(builddir, 'res')
|
||||
icon.writeSize(48, os.path.join(res_dir, 'mipmap-mdpi-v4', basename))
|
||||
icon.writeSize(72, os.path.join(res_dir, 'mipmap-hdpi-v4', basename))
|
||||
icon.writeSize(96, os.path.join(res_dir, 'mipmap-xhdpi-v4', basename))
|
||||
icon.writeSize(144, os.path.join(res_dir, 'mipmap-xxhdpi-v4', basename))
|
||||
|
||||
if icon.getLargestSize() >= 192:
|
||||
icon.writeSize(192, os.path.join(res_dir, 'mipmap-xxxhdpi-v4', basename))
|
||||
|
||||
# Bundle into an .app on macOS
|
||||
if self.macos_main_app and 'macosx' in platform:
|
||||
self.bundle_macos_app(builddir)
|
||||
|
||||
def add_dependency(self, name, target_dir, search_path, referenced_by):
|
||||
""" Searches for the given DLL on the search path. If it exists,
|
||||
copies it to the target_dir. """
|
||||
@ -1533,13 +1549,7 @@ class bdist_apps(setuptools.Command):
|
||||
'manylinux1_i686': ['gztar'],
|
||||
'manylinux2010_x86_64': ['gztar'],
|
||||
'manylinux2010_i686': ['gztar'],
|
||||
'android_arm64': ['aab'],
|
||||
'android_armv7a': ['aab'],
|
||||
'android_arm': ['aab'],
|
||||
'android_mips': ['aab'],
|
||||
'android_mips64': ['aab'],
|
||||
'android_x86': ['aab'],
|
||||
'android_x86_64': ['aab'],
|
||||
'android': ['aab'],
|
||||
# Everything else defaults to ['zip']
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user