浏览代码

makewheel changes for macOS, manylinux1, Python 2.6

rdb 9 年之前
父节点
当前提交
23a345437a
共有 1 个文件被更改,包括 68 次插入45 次删除
  1. 68 45
      makepanda/makewheel.py

+ 68 - 45
makepanda/makewheel.py

@@ -3,9 +3,11 @@ Generates a wheel (.whl) file from the output of makepanda.
 
 Since the wheel requires special linking, this will only work if compiled with
 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 as get_dist
+from distutils.util import get_platform
 import json
 
 import sys
@@ -16,20 +18,18 @@ import zipfile
 import hashlib
 import tempfile
 import subprocess
-from sysconfig import get_config_var
+from distutils.sysconfig import get_config_var
 from optparse import OptionParser
 from makepandacore import ColorText, LocateBinary, ParsePandaVersion, GetExtensionSuffix, SetVerbose, GetVerbose
 from base64 import urlsafe_b64encode
 
 
-def get_platform():
-    p = get_dist().replace('-', '_').replace('.', '_')
-    #if "linux" in p:
-    #    print(ColorText("red", "WARNING:") +
-    #          " Linux-specific wheel files are not supported."
-    #          " We will generate this wheel as a generic package instead.")
-    #    return "any"
-    return p
+default_platform = get_platform()
+
+if default_platform.startswith("linux-"):
+    # Is this manylinux1?
+    if os.path.isfile("/lib/libc-2.5.so") and os.path.isdir("/opt/python"):
+        default_platform = platform.replace("linux", "manylinux1")
 
 
 def get_abi_tag():
@@ -71,7 +71,9 @@ def is_elf_file(path):
 def is_mach_o_file(path):
     base = os.path.basename(path)
     return os.path.isfile(path) and '.' not in base and \
-           open(path, 'rb').read(4) == b'\xCA\xFE\xBA\xBE'
+           open(path, 'rb').read(4) in (b'\xCA\xFE\xBA\xBE', b'\xBE\xBA\xFE\bCA',
+                                        b'\xFE\xED\xFA\xCE', b'\xCE\xFA\xED\xFE',
+                                        b'\xFE\xED\xFA\xCF', b'\xCF\xFA\xED\xFE')
 
 
 if sys.platform in ('win32', 'cygwin'):
@@ -83,18 +85,17 @@ else:
 
 
 # Other global parameters
-PY_VERSION = "cp{}{}".format(sys.version_info.major, sys.version_info.minor)
+PY_VERSION = "cp{0}{1}".format(*sys.version_info)
 ABI_TAG = get_abi_tag()
-PLATFORM_TAG = get_platform()
 EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
 
 # Plug-ins to install.
-PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"]
+PLUGIN_LIBS = ["pandagl", "pandagles", "pandagles2", "pandadx9", "p3tinydisplay", "p3ptloader", "p3assimp", "p3ffmpeg", "p3openal_audio", "p3fmod_audio"]
 
 WHEEL_DATA = """Wheel-Version: 1.0
 Generator: makepanda
 Root-Is-Purelib: false
-Tag: {}-{}-{}
+Tag: {0}-{1}-{2}
 """
 
 METADATA = {
@@ -234,7 +235,11 @@ def scan_dependencies(pathname):
     else:
         command = ['ldd', pathname]
 
-    output = subprocess.check_output(command, universal_newlines=True)
+    process = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)
+    output, unused_err = process.communicate()
+    retcode = process.poll()
+    if retcode:
+        raise subprocess.CalledProcessError(retcode, command[0], output=output)
     filenames = None
 
     if sys.platform in ("win32", "cygwin"):
@@ -245,16 +250,21 @@ 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:
+        # Filter out the library ID.
+        if os.path.basename(filenames[0]).split('.', 1)[0] == os.path.basename(pathname).split('.', 1)[0]:
+            del filenames[0]
+
     return filenames
 
 
 class WheelFile(object):
-    def __init__(self, name, version):
+    def __init__(self, name, version, platform):
         self.name = name
         self.version = version
 
-        wheel_name = "{}-{}-{}-{}-{}.whl".format(
-            name, version, PY_VERSION, ABI_TAG, PLATFORM_TAG)
+        wheel_name = "{0}-{1}-{2}-{3}-{4}.whl".format(
+            name, version, PY_VERSION, ABI_TAG, platform)
 
         print("Writing %s" % (wheel_name))
         self.zip_file = zipfile.ZipFile(wheel_name, 'w', zipfile.ZIP_DEFLATED)
@@ -279,6 +289,10 @@ class WheelFile(object):
             # Don't include the Python library.
             return
 
+        if sys.platform == "darwin" and dep.endswith(".so"):
+            # Temporary hack for 1.9, which had link deps on modules.
+            return
+
         source_path = None
 
         if search_path is None:
@@ -372,7 +386,7 @@ class WheelFile(object):
         # Save it in PEP-0376 format for writing out later.
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = digest.rstrip('=')
-        self.records.append("{},sha256={},{}\n".format(target_path, digest, size))
+        self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, size))
 
         if GetVerbose():
             print("Adding %s from %s" % (target_path, source_path))
@@ -388,7 +402,7 @@ class WheelFile(object):
         sha.update(source_data.encode())
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = digest.rstrip('=')
-        self.records.append("{},sha256={},{}\n".format(target_path, digest, len(source_data)))
+        self.records.append("{0},sha256={1},{2}\n".format(target_path, digest, len(source_data)))
 
         if GetVerbose():
             print("Adding %s from data" % target_path)
@@ -409,18 +423,20 @@ class WheelFile(object):
 
     def close(self):
         # Write the RECORD file.
-        record_file = "{}-{}.dist-info/RECORD".format(self.name, self.version)
+        record_file = "{0}-{1}.dist-info/RECORD".format(self.name, self.version)
         self.records.append(record_file + ",,\n")
 
         self.zip_file.writestr(record_file, "".join(self.records))
         self.zip_file.close()
 
 
-def makewheel(version, output_dir):
+def makewheel(version, output_dir, platform=default_platform):
     if sys.platform not in ("win32", "darwin") and not sys.platform.startswith("cygwin"):
         if not LocateBinary("patchelf"):
             raise Exception("patchelf is required when building a Linux wheel.")
 
+    platform = platform.replace('-', '_').replace('.', '_')
+
     # Global filepaths
     panda3d_dir = join(output_dir, "panda3d")
     pandac_dir = join(output_dir, "pandac")
@@ -438,8 +454,8 @@ def makewheel(version, output_dir):
     # Update relevant METADATA entries
     METADATA['version'] = version
     version_classifiers = [
-        "Programming Language :: Python :: {}".format(*sys.version_info),
-        "Programming Language :: Python :: {}.{}".format(*sys.version_info),
+        "Programming Language :: Python :: {0}".format(*sys.version_info),
+        "Programming Language :: Python :: {0}.{1}".format(*sys.version_info),
     ]
     METADATA['classifiers'].extend(version_classifiers)
 
@@ -454,14 +470,14 @@ def makewheel(version, output_dir):
         "Version: {version}\n" \
         "Summary: {summary}\n" \
         "License: {license}\n".format(**METADATA),
-        "Home-page: {}\n".format(homepage),
-        "Author: {}\n".format(author),
-        "Author-email: {}\n".format(email),
-        "Platform: {}\n".format(PLATFORM_TAG),
-    ] + ["Classifier: {}\n".format(c) for c in METADATA['classifiers']])
+        "Home-page: {0}\n".format(homepage),
+        "Author: {0}\n".format(author),
+        "Author-email: {0}\n".format(email),
+        "Platform: {0}\n".format(platform),
+    ] + ["Classifier: {0}\n".format(c) for c in METADATA['classifiers']])
 
     # Zip it up and name it the right thing
-    whl = WheelFile('panda3d', version)
+    whl = WheelFile('panda3d', version, platform)
     whl.lib_path = [libs_dir]
 
     # Add the trees with Python modules.
@@ -479,11 +495,12 @@ def makewheel(version, output_dir):
         elif file.endswith(ext_suffix) or file.endswith('.py'):
             source_path = os.path.join(panda3d_dir, file)
 
-            if file.endswith('.pyd') and PLATFORM_TAG.startswith('cygwin'):
+            if file.endswith('.pyd') and platform.startswith('cygwin'):
                 # Rename it to .dll for cygwin Python to be able to load it.
                 target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
             else:
                 target_path = 'panda3d/' + file
+
             whl.write_file(target_path, source_path)
 
     # Add plug-ins.
@@ -499,6 +516,16 @@ def makewheel(version, output_dir):
         if os.path.isfile(plugin_path):
             whl.write_file('panda3d/' + plugin_name, plugin_path)
 
+    # Add the .data directory, containing additional files.
+    data_dir = 'panda3d-{0}.data'.format(version)
+    #whl.write_directory(data_dir + '/data/etc', etc_dir)
+    #whl.write_directory(data_dir + '/data/models', models_dir)
+
+    # Actually, let's not.  That seems to install the files to the strangest
+    # places in the user's filesystem.  Let's instead put them in panda3d.
+    whl.write_directory('panda3d/etc', etc_dir)
+    whl.write_directory('panda3d/models', models_dir)
+
     # Add the pandac tree for backward compatibility.
     for file in os.listdir(pandac_dir):
         if file.endswith('.py'):
@@ -506,8 +533,14 @@ def makewheel(version, output_dir):
 
     # Add a panda3d-tools directory containing the executables.
     entry_points = '[console_scripts]\n'
+    entry_points += 'eggcacher = direct.directscripts.eggcacher:main\n'
+    entry_points += 'packpanda = direct.directscripts.packpanda:main\n'
     tools_init = ''
     for file in os.listdir(bin_dir):
+        basename = os.path.splitext(file)[0]
+        if basename in ('eggcacher', 'packpanda'):
+            continue
+
         source_path = os.path.join(bin_dir, file)
 
         if is_executable(source_path):
@@ -515,29 +548,18 @@ def makewheel(version, output_dir):
             whl.write_file('panda3d_tools/' + file, source_path)
 
             # Tell pip to create a wrapper script.
-            basename = os.path.splitext(file)[0]
             funcname = basename.replace('-', '_')
             entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
             tools_init += '{0} = lambda: _exec_tool({1!r})\n'.format(funcname, file)
 
     whl.write_file_data('panda3d_tools/__init__.py', PANDA3D_TOOLS_INIT.format(tools_init))
 
-    # Add the .data directory, containing additional files.
-    data_dir = 'panda3d-{}.data'.format(version)
-    #whl.write_directory(data_dir + '/data/etc', etc_dir)
-    #whl.write_directory(data_dir + '/data/models', models_dir)
-
-    # Actually, let's not.  That seems to install the files to the strangest
-    # places in the user's filesystem.  Let's instead put them in panda3d.
-    whl.write_directory('panda3d/etc', etc_dir)
-    whl.write_directory('panda3d/models', models_dir)
-
     # Add the dist-info directory last.
-    info_dir = 'panda3d-{}.dist-info'.format(version)
+    info_dir = 'panda3d-{0}.dist-info'.format(version)
     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_TAG))
+    whl.write_file_data(info_dir + '/WHEEL', WHEEL_DATA.format(PY_VERSION, ABI_TAG, platform))
     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')
@@ -552,6 +574,7 @@ if __name__ == "__main__":
     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: %s)' % (default_platform), default = get_platform())
     (options, args) = parser.parse_args()
 
     SetVerbose(options.verbose)