|
|
@@ -7,47 +7,90 @@ the `--wheel` parameter.
|
|
|
Please keep this file work with Panda3D 1.9 until that reaches EOL.
|
|
|
"""
|
|
|
from __future__ import print_function, unicode_literals
|
|
|
-from distutils.util import get_platform
|
|
|
+import distutils.util
|
|
|
import json
|
|
|
|
|
|
import sys
|
|
|
import os
|
|
|
from os.path import join
|
|
|
-import shutil
|
|
|
import zipfile
|
|
|
import hashlib
|
|
|
import tempfile
|
|
|
import subprocess
|
|
|
+import configparser
|
|
|
from distutils.sysconfig import get_config_var
|
|
|
from optparse import OptionParser
|
|
|
-from makepandacore import ColorText, LocateBinary, ParsePandaVersion, GetExtensionSuffix, SetVerbose, GetVerbose, GetMetadataValue
|
|
|
from base64 import urlsafe_b64encode
|
|
|
|
|
|
+cfg_parser = None
|
|
|
+
|
|
|
+def get_metadata_value(key):
|
|
|
+ global cfg_parser
|
|
|
+ if not cfg_parser:
|
|
|
+ # Parse the metadata from the setup.cfg file.
|
|
|
+ cfg_parser = configparser.ConfigParser()
|
|
|
+ path = os.path.join(os.path.dirname(__file__), '..', 'setup.cfg')
|
|
|
+ assert cfg_parser.read(path), "Could not read setup.cfg file."
|
|
|
+
|
|
|
+ value = cfg_parser.get('metadata', key)
|
|
|
+ if key == 'classifiers':
|
|
|
+ value = value.strip().split('\n')
|
|
|
+ return value
|
|
|
+
|
|
|
+def get_host():
|
|
|
+ """Returns the host platform, ie. the one we're compiling on."""
|
|
|
+ if sys.platform == 'win32' or sys.platform == 'cygwin':
|
|
|
+ # sys.platform is win32 on 64-bits Windows as well.
|
|
|
+ return 'windows'
|
|
|
+ elif sys.platform == 'darwin':
|
|
|
+ return 'darwin'
|
|
|
+ elif sys.platform.startswith('linux'):
|
|
|
+ try:
|
|
|
+ # Python seems to offer no built-in way to check this.
|
|
|
+ osname = subprocess.check_output(["uname", "-o"])
|
|
|
+ if osname.strip().lower() == b'android':
|
|
|
+ return 'android'
|
|
|
+ else:
|
|
|
+ return 'linux'
|
|
|
+ except:
|
|
|
+ return 'linux'
|
|
|
+ elif sys.platform.startswith('freebsd'):
|
|
|
+ return 'freebsd'
|
|
|
+ else:
|
|
|
+ exit('Unrecognized sys.platform: %s' % (sys.platform))
|
|
|
+
|
|
|
+def locate_binary(binary):
|
|
|
+ """
|
|
|
+ Searches the system PATH for the binary.
|
|
|
+ :param binary: Name of the binary to locate.
|
|
|
+ :return: The full path to the binary, or None if not found.
|
|
|
+ """
|
|
|
+ if os.path.isfile(binary):
|
|
|
+ return binary
|
|
|
+
|
|
|
+ if "PATH" not in os.environ or os.environ["PATH"] == "":
|
|
|
+ p = os.defpath
|
|
|
+ else:
|
|
|
+ p = os.environ["PATH"]
|
|
|
|
|
|
-def get_abi_tag():
|
|
|
- if sys.version_info >= (3, 0):
|
|
|
- soabi = get_config_var('SOABI')
|
|
|
- if soabi and soabi.startswith('cpython-'):
|
|
|
- return 'cp' + soabi.split('-')[1]
|
|
|
- elif soabi:
|
|
|
- return soabi.replace('.', '_').replace('-', '_')
|
|
|
-
|
|
|
- soabi = 'cp%d%d' % (sys.version_info[:2])
|
|
|
-
|
|
|
- debug_flag = get_config_var('Py_DEBUG')
|
|
|
- if (debug_flag is None and hasattr(sys, 'gettotalrefcount')) or debug_flag:
|
|
|
- soabi += 'd'
|
|
|
+ pathList = p.split(os.pathsep)
|
|
|
+ suffixes = ['']
|
|
|
|
|
|
- malloc_flag = get_config_var('WITH_PYMALLOC')
|
|
|
- if malloc_flag is None or malloc_flag:
|
|
|
- soabi += 'm'
|
|
|
+ if get_host() == 'windows':
|
|
|
+ if not binary.lower().endswith('.exe') and not binary.lower().endswith('.bat'):
|
|
|
+ # Append .exe if necessary
|
|
|
+ suffixes = ['.exe', '.bat']
|
|
|
|
|
|
- if sys.version_info < (3, 3):
|
|
|
- usize = get_config_var('Py_UNICODE_SIZE')
|
|
|
- if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4:
|
|
|
- soabi += 'u'
|
|
|
+ # On Windows the current directory is always implicitly
|
|
|
+ # searched before anything else on PATH.
|
|
|
+ pathList = ['.'] + pathList
|
|
|
|
|
|
- return soabi
|
|
|
+ for path in pathList:
|
|
|
+ binpath = os.path.join(os.path.expanduser(path), binary)
|
|
|
+ for suffix in suffixes:
|
|
|
+ if os.access(binpath + suffix, os.X_OK):
|
|
|
+ return os.path.abspath(os.path.realpath(binpath + suffix))
|
|
|
+ return None
|
|
|
|
|
|
|
|
|
def is_exe_file(path):
|
|
|
@@ -74,11 +117,6 @@ def is_fat_file(path):
|
|
|
b'\xCA\xFE\xBA\xBF', b'\xBF\xBA\xFE\xCA')
|
|
|
|
|
|
|
|
|
-def get_python_ext_module_dir():
|
|
|
- import _ctypes
|
|
|
- return os.path.dirname(_ctypes.__file__)
|
|
|
-
|
|
|
-
|
|
|
if sys.platform in ('win32', 'cygwin'):
|
|
|
is_executable = is_exe_file
|
|
|
elif sys.platform == 'darwin':
|
|
|
@@ -86,9 +124,117 @@ elif sys.platform == 'darwin':
|
|
|
else:
|
|
|
is_executable = is_elf_file
|
|
|
|
|
|
+
|
|
|
+class TargetInfo:
|
|
|
+ """
|
|
|
+ Holds information about the system the wheel is being prepared for.
|
|
|
+ """
|
|
|
+ def __init__(self,
|
|
|
+ platform_tag=None,
|
|
|
+ soabi='',
|
|
|
+ python_version=None,
|
|
|
+ python_root=sys.exec_prefix,
|
|
|
+ sys_platform=get_host()):
|
|
|
+ """
|
|
|
+ With no arguments, it will be assumed that the target is the same as the
|
|
|
+ host (which will be most cases).
|
|
|
+
|
|
|
+ :param platform_string: The platform tag used in the wheel filename.
|
|
|
+ :param soabi: Value of SOABI from Python's makefile. This isn't really
|
|
|
+ a thing with Python 2.
|
|
|
+ :param python_version: Version of Python we're bundling. Will be
|
|
|
+ inferred from SOABI or the system's python version if not
|
|
|
+ explicitly set.
|
|
|
+ :param python_root: Root of the Python installation containing the
|
|
|
+ libraries to be bundled in deploy_libs.
|
|
|
+ :param sys_platform:
|
|
|
+ """
|
|
|
+ if platform_tag:
|
|
|
+ self.platform_tag = platform_tag
|
|
|
+ else:
|
|
|
+ self.platform_tag = distutils.util.get_platform()
|
|
|
+ if (self.platform_tag.startswith("linux-")
|
|
|
+ and os.path.isfile("/lib/libc-2.5.so")
|
|
|
+ and os.path.isdir("/opt/python")):
|
|
|
+ self.platform_tag = self.platform_tag.replace("linux",
|
|
|
+ "manylinux1")
|
|
|
+
|
|
|
+ self.abi_flags = None
|
|
|
+ self.soabi = soabi
|
|
|
+ self.python_version = python_version
|
|
|
+ self.python_root = python_root
|
|
|
+ self.sys_platform = sys_platform
|
|
|
+
|
|
|
+ self.platform_tag = self.platform_tag.replace('-', '_').replace('.', '_')
|
|
|
+
|
|
|
+ if not self.python_version:
|
|
|
+ if self.soabi:
|
|
|
+ self.python_version = tuple(
|
|
|
+ int(i) for i in self.soabi.split('-')[1].rstrip('mdu')
|
|
|
+ )
|
|
|
+ print("Inferring Python version %s from provided soabi."
|
|
|
+ % str(self.python_version))
|
|
|
+ else:
|
|
|
+ self.python_version = sys.version_info[:2]
|
|
|
+ self.soabi = get_config_var('SOABI')
|
|
|
+ print("Inferring Python version %s from system version."
|
|
|
+ % str(self.python_version))
|
|
|
+ elif type(self.python_version) is str:
|
|
|
+ self.abi_flags = self.python_version.lstrip('0123456789')
|
|
|
+ self.python_version = tuple(int(i) for i in self.python_version.rstrip('mdu'))
|
|
|
+
|
|
|
+ @property
|
|
|
+ def python_ext_module_dir(self):
|
|
|
+ return os.path.join(self.python_root,
|
|
|
+ 'lib/python{}.{}/lib-dynload'
|
|
|
+ .format(*self.python_version))
|
|
|
+
|
|
|
+ @property
|
|
|
+ def python_tag(self):
|
|
|
+ return "cp{0}{1}".format(*self.python_version)
|
|
|
+
|
|
|
+ @property
|
|
|
+ def abi_tag(self):
|
|
|
+ if sys.version_info >= (3, 0) and self.soabi:
|
|
|
+ if self.soabi.startswith('cpython-'):
|
|
|
+ return 'cp' + self.soabi.split('-')[1]
|
|
|
+ return self.soabi.replace('.', '_').replace('-', '_')
|
|
|
+
|
|
|
+ abi_tag = self.python_tag
|
|
|
+
|
|
|
+ if self.abi_flags:
|
|
|
+ return abi_tag + self.abi_flags
|
|
|
+
|
|
|
+ debug_flag = get_config_var('Py_DEBUG')
|
|
|
+ if (debug_flag is None and hasattr(sys,
|
|
|
+ 'gettotalrefcount')) or debug_flag:
|
|
|
+ abi_tag += 'd'
|
|
|
+
|
|
|
+ malloc_flag = get_config_var('WITH_PYMALLOC')
|
|
|
+ if malloc_flag is None or malloc_flag:
|
|
|
+ abi_tag += 'm'
|
|
|
+
|
|
|
+ if sys.version_info < (3, 3):
|
|
|
+ usize = get_config_var('Py_UNICODE_SIZE')
|
|
|
+ if (usize is None and sys.maxunicode == 0x10ffff) or usize == 4:
|
|
|
+ abi_tag += 'u'
|
|
|
+
|
|
|
+ return abi_tag
|
|
|
+
|
|
|
+ @property
|
|
|
+ def extension_suffix(self):
|
|
|
+ if 'ios' in self.platform_tag:
|
|
|
+ return '.so'
|
|
|
+ if self.soabi != '':
|
|
|
+ ext = '.pyd' if self.sys_platform == 'win32' else '.so'
|
|
|
+ return '.' + self.soabi + ext
|
|
|
+
|
|
|
+ import _imp
|
|
|
+ return _imp.extension_suffixes()[0]
|
|
|
+
|
|
|
# Other global parameters
|
|
|
-PY_VERSION = "cp{0}{1}".format(*sys.version_info)
|
|
|
-ABI_TAG = get_abi_tag()
|
|
|
+# PY_VERSION = "cp{0}{1}".format(*sys.version_info)
|
|
|
+# ABI_TAG = get_abi_tag()
|
|
|
EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
|
|
|
|
|
|
# Plug-ins to install.
|
|
|
@@ -119,15 +265,15 @@ Tag: {0}-{1}-{2}
|
|
|
"""
|
|
|
|
|
|
METADATA = {
|
|
|
- "license": GetMetadataValue('license'),
|
|
|
- "name": GetMetadataValue('name'),
|
|
|
+ "license": get_metadata_value('license'),
|
|
|
+ "name": get_metadata_value('name'),
|
|
|
"metadata_version": "2.0",
|
|
|
"generator": "makepanda",
|
|
|
- "summary": GetMetadataValue('description'),
|
|
|
+ "summary": get_metadata_value('description'),
|
|
|
"extensions": {
|
|
|
"python.details": {
|
|
|
"project_urls": {
|
|
|
- "Home": GetMetadataValue('url'),
|
|
|
+ "Home": get_metadata_value('url'),
|
|
|
},
|
|
|
"document_names": {
|
|
|
"license": "LICENSE.txt"
|
|
|
@@ -135,13 +281,13 @@ METADATA = {
|
|
|
"contacts": [
|
|
|
{
|
|
|
"role": "author",
|
|
|
- "name": GetMetadataValue('author'),
|
|
|
- "email": GetMetadataValue('author_email'),
|
|
|
+ "name": get_metadata_value('author'),
|
|
|
+ "email": get_metadata_value('author_email'),
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
},
|
|
|
- "classifiers": GetMetadataValue('classifiers'),
|
|
|
+ "classifiers": get_metadata_value('classifiers'),
|
|
|
}
|
|
|
|
|
|
DESCRIPTION = """
|
|
|
@@ -257,13 +403,13 @@ def parse_dependencies_unix(data):
|
|
|
return filenames
|
|
|
|
|
|
|
|
|
-def scan_dependencies(pathname):
|
|
|
+def scan_dependencies(pathname, target_info):
|
|
|
""" Checks the named file for DLL dependencies, and adds any appropriate
|
|
|
dependencies found into pluginDependencies and dependentFiles. """
|
|
|
|
|
|
- if sys.platform == "darwin":
|
|
|
+ if target_info.sys_platform in ("darwin", "ios"):
|
|
|
command = ['otool', '-XL', pathname]
|
|
|
- elif sys.platform in ("win32", "cygwin"):
|
|
|
+ elif target_info.sys_platform in ("win32", "cygwin"):
|
|
|
command = ['dumpbin', '/dependents', pathname]
|
|
|
else:
|
|
|
command = ['ldd', pathname]
|
|
|
@@ -275,7 +421,7 @@ def scan_dependencies(pathname):
|
|
|
raise subprocess.CalledProcessError(retcode, command[0], output=output)
|
|
|
filenames = None
|
|
|
|
|
|
- if sys.platform in ("win32", "cygwin"):
|
|
|
+ if target_info.sys_platform in ("win32", "cygwin"):
|
|
|
filenames = parse_dependencies_windows(output)
|
|
|
else:
|
|
|
filenames = parse_dependencies_unix(output)
|
|
|
@@ -283,7 +429,7 @@ def scan_dependencies(pathname):
|
|
|
if filenames is None:
|
|
|
sys.exit("Unable to determine dependencies from %s" % (pathname))
|
|
|
|
|
|
- if sys.platform == "darwin" and len(filenames) > 0:
|
|
|
+ if target_info.sys_platform in ("darwin", "ios") and len(filenames) > 0:
|
|
|
# Filter out the library ID.
|
|
|
if os.path.basename(filenames[0]).split('.', 1)[0] == os.path.basename(pathname).split('.', 1)[0]:
|
|
|
del filenames[0]
|
|
|
@@ -292,13 +438,13 @@ def scan_dependencies(pathname):
|
|
|
|
|
|
|
|
|
class WheelFile(object):
|
|
|
- def __init__(self, name, version, platform):
|
|
|
+ def __init__(self, name, version, target_info):
|
|
|
self.name = name
|
|
|
self.version = version
|
|
|
- self.platform = platform
|
|
|
+ self.target_info = target_info
|
|
|
|
|
|
wheel_name = "{0}-{1}-{2}-{3}-{4}.whl".format(
|
|
|
- name, version, PY_VERSION, ABI_TAG, platform)
|
|
|
+ name, version, target_info.python_tag, target_info.abi_tag, target_info.platform_tag)
|
|
|
|
|
|
print("Writing %s" % (wheel_name))
|
|
|
self.zip_file = zipfile.ZipFile(wheel_name, 'w', zipfile.ZIP_DEFLATED)
|
|
|
@@ -322,15 +468,15 @@ class WheelFile(object):
|
|
|
|
|
|
if dep in self.ignore_deps or dep.lower().startswith("python") or os.path.basename(dep).startswith("libpython"):
|
|
|
# Don't include the Python library, or any other explicit ignore.
|
|
|
- if GetVerbose():
|
|
|
+ if verbose:
|
|
|
print("Ignoring {0} (explicitly ignored)".format(dep))
|
|
|
return
|
|
|
|
|
|
- if sys.platform == "darwin" and dep.endswith(".so"):
|
|
|
+ if target_info.sys_platform in ("darwin", "ios") and dep.endswith(".so"):
|
|
|
# Temporary hack for 1.9, which had link deps on modules.
|
|
|
return
|
|
|
|
|
|
- if sys.platform == "darwin" and dep.startswith("/System/"):
|
|
|
+ if target_info.sys_platform in ("darwin", "ios") and dep.startswith("/System/"):
|
|
|
return
|
|
|
|
|
|
if dep.startswith('/'):
|
|
|
@@ -350,7 +496,7 @@ class WheelFile(object):
|
|
|
|
|
|
if not source_path:
|
|
|
# Couldn't find library in the panda3d lib dir.
|
|
|
- if GetVerbose():
|
|
|
+ if verbose:
|
|
|
print("Ignoring {0} (not in search path)".format(dep))
|
|
|
return
|
|
|
|
|
|
@@ -371,7 +517,7 @@ class WheelFile(object):
|
|
|
|
|
|
# Scan Unix dependencies.
|
|
|
if target_path not in IGNORE_UNIX_DEPS_OF:
|
|
|
- deps = scan_dependencies(source_path)
|
|
|
+ deps = scan_dependencies(source_path, target_info)
|
|
|
else:
|
|
|
deps = []
|
|
|
|
|
|
@@ -384,14 +530,14 @@ class WheelFile(object):
|
|
|
temp = tempfile.NamedTemporaryFile(suffix=suffix, prefix='whl', delete=False)
|
|
|
|
|
|
# On macOS, if no fat wheel was requested, extract the right architecture.
|
|
|
- if sys.platform == "darwin" and is_fat_file(source_path) \
|
|
|
- and not self.platform.endswith("_intel") \
|
|
|
- and "_fat" not in self.platform:
|
|
|
+ if target_info.sys_platform == "darwin" and is_fat_file(source_path) \
|
|
|
+ and not target_info.platform_tag.endswith("_intel") \
|
|
|
+ and "_fat" not in target_info.platform_tag:
|
|
|
|
|
|
- if self.platform.endswith("_x86_64"):
|
|
|
+ if target_info.platform_tag.endswith("_x86_64"):
|
|
|
arch = 'x86_64'
|
|
|
else:
|
|
|
- arch = self.platform.split('_')[-1]
|
|
|
+ arch = target_info.platform_tag.split('_')[-1]
|
|
|
subprocess.call(['lipo', source_path, '-extract', arch, '-output', temp.name])
|
|
|
else:
|
|
|
# Otherwise, just copy it over.
|
|
|
@@ -401,7 +547,7 @@ class WheelFile(object):
|
|
|
os.chmod(temp.name, os.stat(temp.name).st_mode | 0o711)
|
|
|
|
|
|
# Now add dependencies. On macOS, fix @loader_path references.
|
|
|
- if sys.platform == "darwin":
|
|
|
+ if target_info.sys_platform in ("darwin", "ios"):
|
|
|
if source_path.endswith('deploy-stubw'):
|
|
|
deps_path = '@executable_path/../Frameworks'
|
|
|
else:
|
|
|
@@ -411,7 +557,7 @@ class WheelFile(object):
|
|
|
if dep.endswith('/Python'):
|
|
|
# If this references the Python framework, change it
|
|
|
# to reference libpython instead.
|
|
|
- new_dep = deps_path + '/libpython{0}.{1}.dylib'.format(*sys.version_info)
|
|
|
+ new_dep = deps_path + '/libpython{0}.{1}.dylib'.format(*target_info.python_version)
|
|
|
|
|
|
elif '@loader_path' in dep:
|
|
|
dep_path = dep.replace('@loader_path', '.')
|
|
|
@@ -422,6 +568,12 @@ class WheelFile(object):
|
|
|
continue
|
|
|
new_dep = os.path.join(deps_path, os.path.relpath(target_dep, os.path.dirname(target_path)))
|
|
|
|
|
|
+ elif '@rpath' in dep:
|
|
|
+ dep_path = dep.replace('@rpath', '.')
|
|
|
+ target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep)
|
|
|
+ self.consider_add_dependency(target_dep, dep_path)
|
|
|
+ continue
|
|
|
+
|
|
|
elif dep.startswith('/Library/Frameworks/Python.framework/'):
|
|
|
# Add this dependency if it's in the Python directory.
|
|
|
target_dep = os.path.dirname(target_path) + '/' + os.path.basename(dep)
|
|
|
@@ -433,7 +585,7 @@ class WheelFile(object):
|
|
|
|
|
|
else:
|
|
|
if '/' in dep:
|
|
|
- if GetVerbose():
|
|
|
+ if verbose:
|
|
|
print("Ignoring dependency %s" % (dep))
|
|
|
continue
|
|
|
|
|
|
@@ -454,7 +606,7 @@ class WheelFile(object):
|
|
|
ext = ext.lower()
|
|
|
if ext in ('.dll', '.pyd', '.exe'):
|
|
|
# Scan and add Win32 dependencies.
|
|
|
- for dep in scan_dependencies(source_path):
|
|
|
+ for dep in scan_dependencies(source_path, target_info):
|
|
|
target_dep = os.path.dirname(target_path) + '/' + dep
|
|
|
self.consider_add_dependency(target_dep, dep)
|
|
|
|
|
|
@@ -474,7 +626,7 @@ class WheelFile(object):
|
|
|
digest = digest.rstrip('=')
|
|
|
self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, size))
|
|
|
|
|
|
- if GetVerbose():
|
|
|
+ if verbose:
|
|
|
print("Adding {0} from {1}".format(target_path, orig_source_path))
|
|
|
self.zip_file.write(source_path, target_path)
|
|
|
|
|
|
@@ -490,7 +642,7 @@ class WheelFile(object):
|
|
|
digest = digest.rstrip('=')
|
|
|
self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, len(source_data)))
|
|
|
|
|
|
- if GetVerbose():
|
|
|
+ if verbose:
|
|
|
print("Adding %s from data" % target_path)
|
|
|
self.zip_file.writestr(target_path, source_data)
|
|
|
|
|
|
@@ -516,26 +668,11 @@ class WheelFile(object):
|
|
|
self.zip_file.close()
|
|
|
|
|
|
|
|
|
-def makewheel(version, output_dir, platform=None):
|
|
|
- if sys.platform not in ("win32", "darwin") and not sys.platform.startswith("cygwin"):
|
|
|
- if not LocateBinary("patchelf"):
|
|
|
+def makewheel(version, output_dir, target_info):
|
|
|
+ if target_info.sys_platform not in ("win32", "darwin", "ios") and not target_info.sys_platform.startswith("cygwin"):
|
|
|
+ if not locate_binary("patchelf"):
|
|
|
raise Exception("patchelf is required when building a Linux wheel.")
|
|
|
|
|
|
- if platform is None:
|
|
|
- # Determine the platform from the build.
|
|
|
- platform_dat = os.path.join(output_dir, 'tmp', 'platform.dat')
|
|
|
- if os.path.isfile(platform_dat):
|
|
|
- platform = open(platform_dat, 'r').read().strip()
|
|
|
- else:
|
|
|
- print("Could not find platform.dat in build directory")
|
|
|
- platform = get_platform()
|
|
|
- if platform.startswith("linux-"):
|
|
|
- # Is this manylinux1?
|
|
|
- if os.path.isfile("/lib/libc-2.5.so") and os.path.isdir("/opt/python"):
|
|
|
- platform = platform.replace("linux", "manylinux1")
|
|
|
-
|
|
|
- platform = platform.replace('-', '_').replace('.', '_')
|
|
|
-
|
|
|
# Global filepaths
|
|
|
panda3d_dir = join(output_dir, "panda3d")
|
|
|
pandac_dir = join(output_dir, "pandac")
|
|
|
@@ -543,7 +680,7 @@ def makewheel(version, output_dir, platform=None):
|
|
|
models_dir = join(output_dir, "models")
|
|
|
etc_dir = join(output_dir, "etc")
|
|
|
bin_dir = join(output_dir, "bin")
|
|
|
- if sys.platform == "win32":
|
|
|
+ if target_info.sys_platform == "win32":
|
|
|
libs_dir = join(output_dir, "bin")
|
|
|
else:
|
|
|
libs_dir = join(output_dir, "lib")
|
|
|
@@ -567,24 +704,24 @@ def makewheel(version, output_dir, platform=None):
|
|
|
"Home-page: {0}\n".format(homepage),
|
|
|
"Author: {0}\n".format(author),
|
|
|
"Author-email: {0}\n".format(email),
|
|
|
- "Platform: {0}\n".format(platform),
|
|
|
+ "Platform: {0}\n".format(target_info.platform_tag),
|
|
|
] + ["Classifier: {0}\n".format(c) for c in METADATA['classifiers']])
|
|
|
|
|
|
metadata += '\n' + DESCRIPTION.strip() + '\n'
|
|
|
|
|
|
# Zip it up and name it the right thing
|
|
|
- whl = WheelFile('panda3d', version, platform)
|
|
|
+ whl = WheelFile('panda3d', version, target_info)
|
|
|
whl.lib_path = [libs_dir]
|
|
|
|
|
|
- if sys.platform == "win32":
|
|
|
+ if target_info.sys_platform == 'win32':
|
|
|
whl.lib_path.append(join(output_dir, "python", "DLLs"))
|
|
|
|
|
|
- if platform.startswith("manylinux"):
|
|
|
+ if target_info.platform_tag.startswith("manylinux"):
|
|
|
# On manylinux1, we pick up all libraries except for the ones specified
|
|
|
# by the manylinux1 ABI.
|
|
|
whl.lib_path.append("/usr/local/lib")
|
|
|
|
|
|
- if platform.endswith("_x86_64"):
|
|
|
+ if target_info.platform_tag.endswith("_x86_64"):
|
|
|
whl.lib_path += ["/lib64", "/usr/lib64"]
|
|
|
else:
|
|
|
whl.lib_path += ["/lib", "/usr/lib"]
|
|
|
@@ -601,7 +738,7 @@ def makewheel(version, output_dir, platform=None):
|
|
|
__version__ = '{0}'
|
|
|
""".format(version)
|
|
|
|
|
|
- if '27' in ABI_TAG:
|
|
|
+ if (2, 7) in target_info.python_version:
|
|
|
p3d_init += """
|
|
|
if __debug__:
|
|
|
import sys
|
|
|
@@ -614,8 +751,7 @@ if __debug__:
|
|
|
|
|
|
whl.write_file_data('panda3d/__init__.py', p3d_init)
|
|
|
|
|
|
- # Copy the extension modules from the panda3d directory.
|
|
|
- ext_suffix = GetExtensionSuffix()
|
|
|
+ ext_suffix = target_info.extension_suffix
|
|
|
|
|
|
for file in os.listdir(panda3d_dir):
|
|
|
if file == '__init__.py':
|
|
|
@@ -623,7 +759,7 @@ if __debug__:
|
|
|
elif file.endswith('.py') or (file.endswith(ext_suffix) and '.' not in file[:-len(ext_suffix)]):
|
|
|
source_path = os.path.join(panda3d_dir, file)
|
|
|
|
|
|
- if file.endswith('.pyd') and platform.startswith('cygwin'):
|
|
|
+ if file.endswith('.pyd') and target_info.sys_platform == 'cygwin':
|
|
|
# Rename it to .dll for cygwin Python to be able to load it.
|
|
|
target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
|
|
|
else:
|
|
|
@@ -633,27 +769,28 @@ if __debug__:
|
|
|
|
|
|
# And copy the extension modules from the Python installation into the
|
|
|
# deploy_libs directory, for use by deploy-ng.
|
|
|
- ext_suffix = '.pyd' if sys.platform in ('win32', 'cygwin') else '.so'
|
|
|
- ext_mod_dir = get_python_ext_module_dir()
|
|
|
+ ext_suffix = '.pyd' if target_info.sys_platform in ('win32', 'cygwin') else '.so'
|
|
|
+ ext_mod_dir = target_info.python_ext_module_dir
|
|
|
|
|
|
- for file in os.listdir(ext_mod_dir):
|
|
|
- if file.endswith(ext_suffix):
|
|
|
- source_path = os.path.join(ext_mod_dir, file)
|
|
|
+ if not 'ios' in target_info.platform_tag:
|
|
|
+ for file in os.listdir(ext_mod_dir):
|
|
|
+ if file.endswith(ext_suffix):
|
|
|
+ source_path = os.path.join(ext_mod_dir, file)
|
|
|
|
|
|
- if file.endswith('.pyd') and platform.startswith('cygwin'):
|
|
|
- # Rename it to .dll for cygwin Python to be able to load it.
|
|
|
- target_path = 'deploy_libs/' + os.path.splitext(file)[0] + '.dll'
|
|
|
- else:
|
|
|
- target_path = 'deploy_libs/' + file
|
|
|
+ if file.endswith('.pyd') and target_info.sys_platform == 'cygwin':
|
|
|
+ # Rename it to .dll for cygwin Python to be able to load it.
|
|
|
+ target_path = 'deploy_libs/' + os.path.splitext(file)[0] + '.dll'
|
|
|
+ else:
|
|
|
+ target_path = 'deploy_libs/' + file
|
|
|
|
|
|
- whl.write_file(target_path, source_path)
|
|
|
+ whl.write_file(target_path, source_path)
|
|
|
|
|
|
# Add plug-ins.
|
|
|
for lib in PLUGIN_LIBS:
|
|
|
plugin_name = 'lib' + lib
|
|
|
- if sys.platform in ('win32', 'cygwin'):
|
|
|
+ if target_info.sys_platform in ('win32', 'cygwin'):
|
|
|
plugin_name += '.dll'
|
|
|
- elif sys.platform == 'darwin':
|
|
|
+ elif target_info.sys_platform in ('darwin', 'ios'):
|
|
|
plugin_name += '.dylib'
|
|
|
else:
|
|
|
plugin_name += '.so'
|
|
|
@@ -707,18 +844,34 @@ if __debug__:
|
|
|
whl.write_file_data(info_dir + '/entry_points.txt', entry_points)
|
|
|
whl.write_file_data(info_dir + '/metadata.json', json.dumps(METADATA, indent=4, separators=(',', ': ')))
|
|
|
whl.write_file_data(info_dir + '/METADATA', metadata)
|
|
|
- whl.write_file_data(info_dir + '/WHEEL', WHEEL_DATA.format(PY_VERSION, ABI_TAG, platform))
|
|
|
+ whl.write_file_data(info_dir + '/WHEEL', WHEEL_DATA.format(target_info.python_tag, target_info.abi_tag, target_info.platform_tag))
|
|
|
whl.write_file(info_dir + '/LICENSE.txt', license_src)
|
|
|
whl.write_file(info_dir + '/README.md', readme_src)
|
|
|
whl.write_file_data(info_dir + '/top_level.txt', 'direct\npanda3d\npandac\npanda3d_tools\n')
|
|
|
|
|
|
# Add libpython for deployment
|
|
|
- if sys.platform in ('win32', 'cygwin'):
|
|
|
+ if target_info.sys_platform in ('win32', 'cygwin'):
|
|
|
pylib_name = 'python{0}{1}.dll'.format(*sys.version_info)
|
|
|
pylib_path = os.path.join(get_config_var('BINDIR'), pylib_name)
|
|
|
- elif sys.platform == 'darwin':
|
|
|
+ elif target_info.sys_platform == 'darwin':
|
|
|
pylib_name = 'libpython{0}.{1}.dylib'.format(*sys.version_info)
|
|
|
pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name)
|
|
|
+ elif target_info.sys_platform == 'ios':
|
|
|
+ archs = ['arm64', 'x86_64']
|
|
|
+ arch = ''
|
|
|
+ for arch_str in archs:
|
|
|
+ if arch_str in target_info.platform_tag:
|
|
|
+ arch = arch_str
|
|
|
+ break
|
|
|
+ else:
|
|
|
+ raise Exception('Platform string does not specify one of ' + archs)
|
|
|
+
|
|
|
+ python_dir = os.path.abspath(join('thirdparty', 'ios-libs-%s' % arch, 'python', 'lib'))
|
|
|
+ pylib_name = ''
|
|
|
+ for filename in os.listdir(python_dir):
|
|
|
+ if os.path.isfile(os.path.join(python_dir, filename)) and 'libpython' in filename and filename.endswith('dylib'):
|
|
|
+ pylib_name = filename
|
|
|
+ pylib_path = join(python_dir, pylib_name)
|
|
|
else:
|
|
|
pylib_name = get_config_var('LDLIBRARY')
|
|
|
pylib_path = os.path.join(get_config_var('LIBDIR'), pylib_name)
|
|
|
@@ -728,14 +881,22 @@ if __debug__:
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
- version = ParsePandaVersion("dtool/PandaVersion.pp")
|
|
|
+ version = get_metadata_value('version')
|
|
|
|
|
|
parser = OptionParser()
|
|
|
parser.add_option('', '--version', dest = 'version', help = 'Panda3D version number (default: %s)' % (version), default = version)
|
|
|
parser.add_option('', '--outputdir', dest = 'outputdir', help = 'Makepanda\'s output directory (default: built)', default = 'built')
|
|
|
parser.add_option('', '--verbose', dest = 'verbose', help = 'Enable verbose output', action = 'store_true', default = False)
|
|
|
- parser.add_option('', '--platform', dest = 'platform', help = 'Override platform tag', default = None)
|
|
|
+ parser.add_option('', '--platform', dest = 'platform_tag', help = 'Override platform tag', default = None)
|
|
|
+ parser.add_option('', '--soabi', dest = 'soabi', help = 'SOABI, used for extension suffixes.')
|
|
|
+ parser.add_option('', '--pyver', dest = 'python_version', help = 'Custom Python version we\'re making the wheel for.')
|
|
|
+ parser.add_option('', '--pyroot', dest = 'python_root', help = 'Custom root of Python installation.', default = sys.exec_prefix)
|
|
|
+ parser.add_option('', '--sysplatform', dest = 'sys_platform', help = 'Output of "sys.platform" on the target', default = get_host())
|
|
|
(options, args) = parser.parse_args()
|
|
|
|
|
|
- SetVerbose(options.verbose)
|
|
|
- makewheel(options.version, options.outputdir, options.platform)
|
|
|
+ ti_opts = {key: options.__dict__[key] for key in ('platform_tag', 'soabi', 'python_version', 'python_root', 'sys_platform')}
|
|
|
+ target_info = TargetInfo(**ti_opts)
|
|
|
+
|
|
|
+ global verbose
|
|
|
+ verbose = options.verbose
|
|
|
+ makewheel(options.version, options.outputdir, target_info)
|