Browse Source

makewheel changes for macOS, manylinux1, Python 2.6

rdb 9 years ago
parent
commit
23a345437a
1 changed files with 68 additions and 45 deletions
  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
 Since the wheel requires special linking, this will only work if compiled with
 the `--wheel` parameter.
 the `--wheel` parameter.
+
+Please keep this file work with Panda3D 1.9 until that reaches EOL.
 """
 """
 from __future__ import print_function, unicode_literals
 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 json
 
 
 import sys
 import sys
@@ -16,20 +18,18 @@ import zipfile
 import hashlib
 import hashlib
 import tempfile
 import tempfile
 import subprocess
 import subprocess
-from sysconfig import get_config_var
+from distutils.sysconfig import get_config_var
 from optparse import OptionParser
 from optparse import OptionParser
 from makepandacore import ColorText, LocateBinary, ParsePandaVersion, GetExtensionSuffix, SetVerbose, GetVerbose
 from makepandacore import ColorText, LocateBinary, ParsePandaVersion, GetExtensionSuffix, SetVerbose, GetVerbose
 from base64 import urlsafe_b64encode
 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():
 def get_abi_tag():
@@ -71,7 +71,9 @@ def is_elf_file(path):
 def is_mach_o_file(path):
 def is_mach_o_file(path):
     base = os.path.basename(path)
     base = os.path.basename(path)
     return os.path.isfile(path) and '.' not in base and \
     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'):
 if sys.platform in ('win32', 'cygwin'):
@@ -83,18 +85,17 @@ else:
 
 
 
 
 # Other global parameters
 # 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()
 ABI_TAG = get_abi_tag()
-PLATFORM_TAG = get_platform()
 EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
 EXCLUDE_EXT = [".pyc", ".pyo", ".N", ".prebuilt", ".xcf", ".plist", ".vcproj", ".sln"]
 
 
 # Plug-ins to install.
 # 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
 WHEEL_DATA = """Wheel-Version: 1.0
 Generator: makepanda
 Generator: makepanda
 Root-Is-Purelib: false
 Root-Is-Purelib: false
-Tag: {}-{}-{}
+Tag: {0}-{1}-{2}
 """
 """
 
 
 METADATA = {
 METADATA = {
@@ -234,7 +235,11 @@ def scan_dependencies(pathname):
     else:
     else:
         command = ['ldd', pathname]
         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
     filenames = None
 
 
     if sys.platform in ("win32", "cygwin"):
     if sys.platform in ("win32", "cygwin"):
@@ -245,16 +250,21 @@ def scan_dependencies(pathname):
     if filenames is None:
     if filenames is None:
         sys.exit("Unable to determine dependencies from %s" % (pathname))
         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
     return filenames
 
 
 
 
 class WheelFile(object):
 class WheelFile(object):
-    def __init__(self, name, version):
+    def __init__(self, name, version, platform):
         self.name = name
         self.name = name
         self.version = version
         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))
         print("Writing %s" % (wheel_name))
         self.zip_file = zipfile.ZipFile(wheel_name, 'w', zipfile.ZIP_DEFLATED)
         self.zip_file = zipfile.ZipFile(wheel_name, 'w', zipfile.ZIP_DEFLATED)
@@ -279,6 +289,10 @@ class WheelFile(object):
             # Don't include the Python library.
             # Don't include the Python library.
             return
             return
 
 
+        if sys.platform == "darwin" and dep.endswith(".so"):
+            # Temporary hack for 1.9, which had link deps on modules.
+            return
+
         source_path = None
         source_path = None
 
 
         if search_path is None:
         if search_path is None:
@@ -372,7 +386,7 @@ class WheelFile(object):
         # Save it in PEP-0376 format for writing out later.
         # Save it in PEP-0376 format for writing out later.
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = digest.rstrip('=')
         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():
         if GetVerbose():
             print("Adding %s from %s" % (target_path, source_path))
             print("Adding %s from %s" % (target_path, source_path))
@@ -388,7 +402,7 @@ class WheelFile(object):
         sha.update(source_data.encode())
         sha.update(source_data.encode())
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = str(urlsafe_b64encode(sha.digest()))
         digest = digest.rstrip('=')
         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():
         if GetVerbose():
             print("Adding %s from data" % target_path)
             print("Adding %s from data" % target_path)
@@ -409,18 +423,20 @@ class WheelFile(object):
 
 
     def close(self):
     def close(self):
         # Write the RECORD file.
         # 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.records.append(record_file + ",,\n")
 
 
         self.zip_file.writestr(record_file, "".join(self.records))
         self.zip_file.writestr(record_file, "".join(self.records))
         self.zip_file.close()
         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 sys.platform not in ("win32", "darwin") and not sys.platform.startswith("cygwin"):
         if not LocateBinary("patchelf"):
         if not LocateBinary("patchelf"):
             raise Exception("patchelf is required when building a Linux wheel.")
             raise Exception("patchelf is required when building a Linux wheel.")
 
 
+    platform = platform.replace('-', '_').replace('.', '_')
+
     # Global filepaths
     # Global filepaths
     panda3d_dir = join(output_dir, "panda3d")
     panda3d_dir = join(output_dir, "panda3d")
     pandac_dir = join(output_dir, "pandac")
     pandac_dir = join(output_dir, "pandac")
@@ -438,8 +454,8 @@ def makewheel(version, output_dir):
     # Update relevant METADATA entries
     # Update relevant METADATA entries
     METADATA['version'] = version
     METADATA['version'] = version
     version_classifiers = [
     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)
     METADATA['classifiers'].extend(version_classifiers)
 
 
@@ -454,14 +470,14 @@ def makewheel(version, output_dir):
         "Version: {version}\n" \
         "Version: {version}\n" \
         "Summary: {summary}\n" \
         "Summary: {summary}\n" \
         "License: {license}\n".format(**METADATA),
         "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
     # Zip it up and name it the right thing
-    whl = WheelFile('panda3d', version)
+    whl = WheelFile('panda3d', version, platform)
     whl.lib_path = [libs_dir]
     whl.lib_path = [libs_dir]
 
 
     # Add the trees with Python modules.
     # Add the trees with Python modules.
@@ -479,11 +495,12 @@ def makewheel(version, output_dir):
         elif file.endswith(ext_suffix) or file.endswith('.py'):
         elif file.endswith(ext_suffix) or file.endswith('.py'):
             source_path = os.path.join(panda3d_dir, file)
             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.
                 # Rename it to .dll for cygwin Python to be able to load it.
                 target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
                 target_path = 'panda3d/' + os.path.splitext(file)[0] + '.dll'
             else:
             else:
                 target_path = 'panda3d/' + file
                 target_path = 'panda3d/' + file
+
             whl.write_file(target_path, source_path)
             whl.write_file(target_path, source_path)
 
 
     # Add plug-ins.
     # Add plug-ins.
@@ -499,6 +516,16 @@ def makewheel(version, output_dir):
         if os.path.isfile(plugin_path):
         if os.path.isfile(plugin_path):
             whl.write_file('panda3d/' + plugin_name, 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.
     # Add the pandac tree for backward compatibility.
     for file in os.listdir(pandac_dir):
     for file in os.listdir(pandac_dir):
         if file.endswith('.py'):
         if file.endswith('.py'):
@@ -506,8 +533,14 @@ def makewheel(version, output_dir):
 
 
     # Add a panda3d-tools directory containing the executables.
     # Add a panda3d-tools directory containing the executables.
     entry_points = '[console_scripts]\n'
     entry_points = '[console_scripts]\n'
+    entry_points += 'eggcacher = direct.directscripts.eggcacher:main\n'
+    entry_points += 'packpanda = direct.directscripts.packpanda:main\n'
     tools_init = ''
     tools_init = ''
     for file in os.listdir(bin_dir):
     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)
         source_path = os.path.join(bin_dir, file)
 
 
         if is_executable(source_path):
         if is_executable(source_path):
@@ -515,29 +548,18 @@ def makewheel(version, output_dir):
             whl.write_file('panda3d_tools/' + file, source_path)
             whl.write_file('panda3d_tools/' + file, source_path)
 
 
             # Tell pip to create a wrapper script.
             # Tell pip to create a wrapper script.
-            basename = os.path.splitext(file)[0]
             funcname = basename.replace('-', '_')
             funcname = basename.replace('-', '_')
             entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
             entry_points += '{0} = panda3d_tools:{1}\n'.format(basename, funcname)
             tools_init += '{0} = lambda: _exec_tool({1!r})\n'.format(funcname, file)
             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))
     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.
     # 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 + '/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.json', json.dumps(METADATA, indent=4, separators=(',', ': ')))
     whl.write_file_data(info_dir + '/METADATA', metadata)
     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 + '/LICENSE.txt', license_src)
     whl.write_file(info_dir + '/README.md', readme_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')
     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('', '--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('', '--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('', '--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()
     (options, args) = parser.parse_args()
 
 
     SetVerbose(options.verbose)
     SetVerbose(options.verbose)