setup.py: don't rewrite @LIBDIR@ when creating wheels
authorGregory Szorc <gregory.szorc@gmail.com>
Sat, 05 Dec 2015 17:52:50 -0800
changeset 27269 bdcbec65750b
parent 27268 ed1660ce99d9
child 27270 ba5f20450b10
setup.py: don't rewrite @LIBDIR@ when creating wheels This is necessary to produce wheels that install properly. More details are captured in an in-line comment. After this patch, produced wheels can be installed via `pip install` and appear to "just work," including on Windows.
setup.py
--- a/setup.py	Fri Dec 04 00:24:48 2015 -0800
+++ b/setup.py	Sat Dec 05 17:52:50 2015 -0800
@@ -479,6 +479,25 @@
     def run(self):
         install_scripts.run(self)
 
+        # It only makes sense to replace @LIBDIR@ with the install path if
+        # the install path is known. For wheels, the logic below calculates
+        # the libdir to be "../..". This is because the internal layout of a
+        # wheel archive looks like:
+        #
+        #   mercurial-3.6.1.data/scripts/hg
+        #   mercurial/__init__.py
+        #
+        # When installing wheels, the subdirectories of the "<pkg>.data"
+        # directory are translated to system local paths and files therein
+        # are copied in place. The mercurial/* files are installed into the
+        # site-packages directory. However, the site-packages directory
+        # isn't known until wheel install time. This means we have no clue
+        # at wheel generation time what the installed site-packages directory
+        # will be. And, wheels don't appear to provide the ability to register
+        # custom code to run during wheel installation. This all means that
+        # we can't reliably set the libdir in wheels: the default behavior
+        # of looking in sys.path must do.
+
         if (os.path.splitdrive(self.install_dir)[0] !=
             os.path.splitdrive(self.install_lib)[0]):
             # can't make relative paths from one drive to another, so use an
@@ -500,6 +519,14 @@
             if b('\0') in data:
                 continue
 
+            # During local installs, the shebang will be rewritten to the final
+            # install path. During wheel packaging, the shebang has a special
+            # value.
+            if data.startswith(b'#!python'):
+                log.info('not rewriting @LIBDIR@ in %s because install path '
+                         'not known' % outfile)
+                continue
+
             data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
             fp = open(outfile, 'wb')
             fp.write(data)