26

我讨厌distutils的一件事(我猜他是这样做的邪恶)是它改变了 shebang 线。换句话说,更理性和环境变量决定经文

#!/usr/bin/env python

神奇地转换成

#!/whatever/absolute/path/is/my/python

这在 grok 中也可以看到:我在 virtualenv 中使用 grokproject 来启动我的项目,但现在我不能再移动开发目录了,因为它将绝对路径放在 shebang 指令中。

我问这个的原因是双重的

  • 我想移动它,因为我开始在一个目录(实验)中开发,现在我想将它移动到正确的路径,但我做不到。所以我创建了一个新的 virtualenv 和 grokproject 并复制了我的文件。这解决了这个问题,但让我对更合理的解决方案的好奇心得不到满足。特别是,如果对 virtualenv python 解释器的引用是相对的,那么问题一开始就不会出现。你知道virtualenv的布局,你可以很容易地参考virtualenv python。
  • 第二个原因是我希望能够将 virtualenv scp 到另一台计算机并在那里运行它而不会遇到麻烦。如果您有硬编码的路径,这是不可能的。
4

5 回答 5

14

当然,您可以移动开发目录。Distutils 更改运行时应该使用的 python 的路径。当您运行构建时,它在 Grok 运行中。移动并重新运行引导程序和构建。完毕!

Distutils 更改了用于运行 distutils 的 Python 的路径。如果没有,那么您最终可能会在一个 python 版本中安装一个库,但是当您尝试运行脚本时它会失败,因为它将与另一个没有该库的 python 版本一起运行。

这不是精神错乱,实际上这是唯一理智的方法。

更新:如果你知道你在做什么,你可以这样做:

/path/to/install/python setup.py build -e "/the/path/you/want/python" install

不过,请确保先清理构建目录。:)

于 2009-10-07T10:37:09.763 回答
12

Distutils 将自动将 shebang 替换为用于执行 setup.py 的 Python 二进制文件的位置。要覆盖此行为,您有两种选择:

选项 1:手动

您可以将标志--executable=/path/to/my/python传递给 setup.py。参数被接受。

例子:

% python setup.py build --executable=/opt/local/bin/python -d

选项 2:自动

您的另一个选择是在 setup.cfg 中添加一行。如果您不使用 setup.cfg,请将其创建在与 setup.py 相同的目录中。Setup.py 在启动时查找它。此处指定的任何选项仍然可以在命令行中用标志覆盖。

% cat setup.cfg 
[build]
executable = /opt/local/bin/python -d
于 2009-11-12T05:01:14.747 回答
2

我无法解决您的问题,但我确实看到了distutils当前行为的一些理由。

#!/usr/bin/env python执行系统的默认 Python 版本。只要您的代码与所述版本兼容,就可以了。当默认版本更新(例如从 2.5 到 3)时,您的代码或其他引用的 Python 代码/usr/bin/env可能会停止工作,即使仍然安装了旧的 Python 版本。出于这个原因,将路径“硬编码”到适当的 python 解释器是有意义的。

编辑:您断言指定python2.4或类似解决此问题是正确的。

编辑 2:正如Ned Deily在下面的评论中指出的那样,当存在相同 Python 版本的多个安装时,事情并不那么明确。

于 2009-10-07T10:29:42.597 回答
2

distutils的最新版本之一中,有一个标志--no-autoreq对我有用:

--no-autoreq         do not automatically calculate dependencies

在我的例子中,我在一个安装了 2.4 和 2.6 的服务器上创建了带有 python2.4 可执行文件的 RPM 文件。bdist 在运行后就离开了 shebangs:

python setup.py bdist_rpm --no-autoreq

如果您正在处理规范文件,您可以使用https://stackoverflow.com/a/7423994/722997中解释的解决方案,并添加:

AutoReq: no
于 2012-05-07T17:41:58.420 回答
2

有同样的问题。试图找到一种默认情况下完全防止触摸的方法。这是解决方案。本质上我们覆盖了默认的脚本复制例程(build_scripts)。

在 setup.py 添加

from distutils.command.build_scripts import build_scripts

# don't touch my shebang
class BSCommand (build_scripts):
    def run(self):
        """
        Copy, chmod each script listed in 'self.scripts'
        essentially this is the stripped 
         distutils.command.build_scripts.copy_scripts()
        routine
        """
        from stat import ST_MODE
        from distutils.dep_util import newer
        from distutils import log
        import os

        self.mkpath(self.build_dir)
        outfiles = []
        for script in self.scripts:
            outfile = os.path.join(self.build_dir, os.path.basename(script))
            outfiles.append(outfile)

            if not self.force and not newer(script, outfile):
                log.debug("not copying %s (up-to-date)", script)
                continue

            log.info("copying and NOT adjusting %s -> %s", script,
                         self.build_dir)
            self.copy_file(script, outfile)

        if os.name == 'posix':
            for file in outfiles:
                if self.dry_run:
                    log.info("changing mode of %s", file)
                else:
                    oldmode = os.stat(file)[ST_MODE] & 0o7777
                    newmode = (oldmode | 0o555) & 0o7777
                    if newmode != oldmode:
                        log.info("changing mode of %s from %o to %o",
                                 file, oldmode, newmode)
                        os.chmod(file, newmode)

setup(name="name",
      version=version_string,
      description="desc",
      ...
      test_suite='testing',
      cmdclass={'build_scripts': BSCommand},
      )

.. ede/duply.net

于 2015-10-26T12:18:26.127 回答