Pip: 解决与树外构建相关的问题

创建于 2020-01-04  ·  68评论  ·  资料来源: pypa/pip

我打开这个问题试图整合关于树外构建、相关问题和可能的解决方案的讨论。

此功能将解决什么问题?

从本地目录构建项目时,pip 首先将它们复制到一个临时位置

随着时间的推移,这种方法引发了许多问题:

  • 当 setup.py / pyproject.toml 不在项目的根目录下并且构建依赖于 setup.py / pyproject.toml 子树(#3500、#7549、#6276)之外的资源时,例如:

    • 构建需要作为子树外部文件/目录符号链接的资源

    • 构建需要 git 存储库(例如,在使用 setuptools_scm 时),并且 .git/ 位于父目录中,没有通过 pip 复制到临时目录

    • build 依赖于子目录名称(可能有点奇特,但我有这样的情况,我想创建一个自定义构建后端,而部分元数据取决于子目录名称)

  • 项目目录很大时的性能问题 (#2195)。

为什么 pip 在构建之前复制到临时目录? 警告:这对我来说不清楚 - 这是我迄今为止收集的内容:

  • 为了避免依赖源外的东西(https://github.com/pypa/pip/issues/2195#issuecomment-524606986)-尽管“源外”的定义是上述一些问题的原因
  • 避免使用构建工件或残留物(?)污染源目录
  • 还有什么?

可能的解决方案

  1. 就地构建 sdist,将 sdist 解压缩到临时位置,然后从中构建。
  2. 添加 pip 选项以就地构建。
  3. 使用某种机制更新 PEP 517,让后端与前端通信,如果它们对于就地构建是“安全的”。
  4. 将 pip 更改为始终就地构建。
  5. 默认情况下将 pip 更改为就地构建,并带有构建树外的选项。

附加上下文

有关通过 sdist 构建的更多讨论

needs discussion

最有用的评论

来自https://github.com/pypa/pip/issues/2195#issuecomment -664728481 我可以说我很高兴在--use-feature=in-tree-build后面重新做#7882。

所有68条评论

从后端的角度来看,“树外构建”的想法实际上是没有意义的。 后端以进程当前目录的形式给出一个“源代码树”,并被要求执行构建。 无法知道该目录是从 sdist 中提取的、从 VCS 中检出的,还是从其他地方复制的。 它所能做的就是构建,如果它没有构建所需的东西,则报告失败。

所以这几乎扼杀了可能的解决方案(3)IMO - 后端没有关于就地构建什么的概念,所以它不能说这样的构建是否安全1

关于(2),我通常反对像这样的附加选项。 如果我们知道最好的做法是什么,我们就应该去做,如果我们不知道,那么将问题传递给用户并不是一个特别友好的选择。 这里的问题很微妙,我希望很少有用户知道正确的选择是什么,所以我们很可能会看到人们只是尝试这两个选项并盲目地使用“任何有效的方法”。 此外,支持含义很重要——提供一个选项显然意味着我们预计构建结果至少在某些情况下会有所不同,那么我们如何测试这些差异是否符合我们的预期? 我们是否负责教育用户何时需要就地构建标志(通过我们的文档,或者由于不知道使用哪个的用户提出的问题)?

话虽如此,我并不反对简单地就地构建 pip。 我相信我们不这样做的原因是因为我们有这样的情况,即在随后的构建中使用了先前构建遗留的工件,但使用不同的选项构建(例如,在调试模式下构建的目标文件链接到发布构建从同一棵树完成)。 然而,后端应该确保这样的问题不会发生是合理的,如果发生,这是一个后端错误,而不是 pip 试图防御它。 但是,我不确定采取这种立场是否对用户特别友好——这是在 PEP 517 讨论增量构建的主题期间提出的,并且引起了足够的争议,以至于当时被推迟了。

很长一段时间以来,我的偏好是构建一个 sdist,然后从中构建轮子(您的选项 1)。 我对 pip 构建没问题(如果我们同意这样做是安全的,正如我上面提到的,我们不能指望后端让我们知道),但我认为这需要一个社区讨论以消除更广泛的影响(对后端、pip/前端和最终用户)。

1当然可以更新 PEP 517 来定义什么构成“就地”源树而不是“树外”构建,但我怀疑这将是一个非常难以确定的概念。

我添加了解决方案 4.(将 pip 更改为始终就地构建)和 5.(默认情况下将 pip 更改为就地构建,并带有构建树外的选项)。

由于以下原因,我对通过 sdist(解决方案 1.)进行构建的感觉很复杂:

  1. 一些项目可能有一个损坏的 sdist-to-wheel 路径; 虽然我看到了验证从 sdists 构建的价值,但现在默认这样做肯定会破坏很多最终用户的构建
  2. 它仍然对具有大型 sdists 的项目有性能影响,并且由于额外的子流程调用
  3. 我个人认为我们不应该过分强调 sdists,因为项目发布构建的工件并引用他们最喜欢的代码托管平台来发布源代码是很常见的(例如,依赖于存在 VCS 签出的后端)建筑物需要跳过箍以产生工作的 sdist)。 并且 PEP 517 特别允许后端为build_sdist筹集UnsupportedOperation build_sdist

这篇关于讨论的帖子也总结了类似的论点。

我同意解决方案 3 的路径远非显而易见。

我也同意,如果可以的话,我们应该避免额外的选择。

我还注意到在链接的讨论线程中有一些支持就地构建的声音,但如果我们想探索这种方法,确实有必要针对该特定主题进行集中的社区讨论。

  • 就地构建 sdist,将 sdist 解压缩到临时位置,然后从中构建。

我认为这是一个很好的方法。

IMO 的可能性是,在大多数涉及本地目录的pip install运行中,这将针对单个包运行 - 最常见的是我想象的pip install . 。 这可能会作为包开发工作流程的一部分来完成。

这是我认为这种行为应该是:

  • 如果后端无法创建 sdist,请执行 local-dir -> wheel (in-place)

    • 我认为后端有很大的责任确保 local-dir -> wheel 在这种情况下是幂等操作。

  • 如果后端能够创建 sdist,请执行 local-dir -> sdist -> unpacked-sdist -> wheel。

执行 local-dir -> sdist -> wheel,我们确实有一组额外的调用。 但是,我确实认为验证生成的 sdists 是否正常是合理的,尤其是在开发过程中。 tox 已经将其作为其工作流程的一部分,检查清单以覆盖 setuptools 的不那么友好的界面。

总的来说,我确实认为在给定本地目录的情况下构建 sdist 的成本是值得的,以防止项目中出现此类错误,特别是因为从本地目录安装的人很可能是项目的开发人员本身。

关于推出,我想我们想等一下,看看#6536 是如何出现的。 我们肯定会学到一些可以转移的东西。

我更喜欢在没有 sdist 的情况下就地构建/安装(因此setup.py installsetup.py bdist_wheel或在适用的 PEP 517 后端调用build_wheel )与构建 sdist、解包和安装从那。 我的具体原因是:

  1. 支持最大数量的开箱即用用户。

    1. 假设 pip 执行 local-dir -> 安装(通过就地构建轮子或setup.py install )。 想要从 local-dir -> installed 转到的用户可以执行pip install local-dir 。 想要从 local-dir -> sdist -> installed 的用户可以自由地创建一个 sdist 然后执行pip install ./path/to/sdist 。 有很多替代工具可以构建 sdist,除非他们手工制作上传到 PyPI 的发行版,否则用户更有可能已经拥有这种工具。

    2. 现在假设 pip 执行 local-dir -> sdist -> 安装。 想要从 local-dir -> installed 进入的用户没有涉及 pip 的选项。 想要从 local-dir -> sdist -> installed 的用户可以执行pip install local-dir 。 没有选项的用户将要求 pip 提供控制行为的选项,或者必须找到另一个他们不需要的工具。

  2. 如果我们实现 local-dir -> sdist -> installed ,大概我们也会为基于 VCS 的需求而做? 如果是这样,那就是更多的工作。 如果没有,那就是代码中的额外路径和安装处理方式中的偏差,用户或在提供支持时必须记住这些。
  3. 需要执行的工作量最少。 有三个地方可以更改以实现 local-dir -> installed(此处此处此处)。 对于 local-dir -> sdist -> installed 在#6607 完成之前,我什至不想触摸实现它,否则我认为它最终会出现在代码库中的很多地方,类似于工件下载/哈希检查。
  4. 需要测试的工作量最少,因为 IMO,现有测试足以覆盖本地目录 -> 已安装的代码路径。 对于 local-dir -> sdist -> installed 路径,我们希望验证我们实际上正在构建一个 sdist,并且回退可以直接构建一个轮子。
  5. 最少的工作(计算)。 正如在别处提到的, local-dir -> sdist -> installed 是一个额外的子进程调用(并且该子进程正在工作)。 这也意味着 pip 必须在进行轮子构建之前解压缩 sdist(你好病毒扫描程序和其他慢速磁盘)。

不管采用哪种方法,我看到的就地处理的唯一问题是,对于 setuptools 构建(我认为这适用于旧版和 PEP 517),我们最终会在项目目录中得到.egg-info ,这会出错当在该目录中使用python -m pip调用 pip 时,作为“已安装的包”。 这将由 #4575 修复,它可能不会在查询中包含任何方案的已安装软件包的当前目录。

注意到我越来越同意跳过 sdist 构建并直接进行树内构建的想法是 pip 默认采用的更好方法,而不是尝试执行 local-dir -> sdist -> wheel。

在 Fedora 中,当我们构建 Python RPM 包时,我们就像恐龙一样,进行瘦身的标准方法是使用python setup.py build 。 在 PEP 517 中,我们添加了一种使用pip wheel的“临时”方式。 但是,对于扩展模块,我们遇到了 pip 用于构建它们的“将源移动到 tmp,从那里构建”方法的问题。

我们的构建机制正在注入一些编译器标志,因此构建工件(在本例中.so扩展模块)包含有关其源的元数据。 后来有一个 shell 脚本,它遍历构建工件,提取此信息并将源复制到/usr/src/debug以通过特殊的*-debugsource RPM 进行安装。 机械厂希望一切都在工作树中构建,而在外部构建时它并不能很好地工作。 以下是可以(一起)做的事情来缓解我们这边的问题:

  1. $TMPDIR环境变量设置在 RPM 脚本期望它的位置(即export TMPDIR=%{_builddir}/.tmp (并创建它))
  2. 使用pip wheel--no-clean选项将复制的源保存在$TMPDIR
  3. 运行一些 shell kung fu 将“what is my source”信息重写到正确的位置: find %{buildroot} -iname '*.so' -print0 | xargs --no-run-if-empty -0 -n1 /usr/lib/rpm/debugedit -b "%{_builddir}/.tmp/pip-req-build-"* -d "$PWD"
  4. (可选:手动清理$TMPDIR 。)

我们不是特别喜欢第三步,因为它依赖太多的实现细节:

  • /usr/lib/rpm/debugedit API 和位置(和存在)
  • pip-req-build名称
  • pip 构建源的机制

如果 pip 总是就地构建,或者如果有命令行开关,问题就会消失。

下游报告: https : =1806625

注意到我越来越同意跳过 sdist 构建并直接进行树内构建的想法是 pip 默认采用的更好方法,而不是尝试执行 local-dir -> sdist -> wheel。

我也越来越倾向于接受就地构建车轮的想法。 我剩余的保留是:

  1. 我们将依赖后端的“正确”行为——例如,不会根据以前构建的剩余数据或其他任何内容给出不同的结果。 我可以做出这样的假设,但是如果我们开始让人们说“pip 错误地构建了我的轮子”并且我们必须进行调试才发现这是一个后端问题,我会担心支持成本。
  2. 我认为无论我们采取
  3. 作为上述的推论,我们应该确保没有我们知道的项目依赖于我们当前的“复制和构建”方法,就好像我们将通过此更改破坏它们一样。

...当然有人需要写一个 PR 来实现这个变化(包括测试、文档等——通常的东西)否则我们所做的就是谈论 🙂

我们将依赖后端的“正确”行为——例如,不会根据以前构建的剩余数据或其他任何内容给出不同的结果。 我可以做出这样的假设,但是如果我们开始让人们说“pip 错误地构建了我的轮子”并且我们必须进行调试才发现这是一个后端问题,我会担心支持成本。

扩展 PEP 517 接口以包含“干净”的钩子是否有意义? 无论如何,我们可能希望它作为某个点来启用其他努力(例如,实现可编辑安装,构建构建任何 PEP 517 项目的包开发工具)。 pip 可以在这里调用它以确保在进行树内构建之前没有剩余的垃圾。

扩展 PEP 517 接口以包含“干净”的钩子是否有意义?

也许? 但是,如果PIP自动调用clean ,有必然是人谁愿意这样做,要做增量编译或东西。 然后我们以另一种选择结束。

我倾向于坚持我的立场“我们需要能够假设后端有责任确保就地构建正确工作”。 即使结果证明这是站不住脚的,获得具体的例子来说明为什么它不起作用将帮助我们更好地理解如何处理这个问题,而不仅仅是猜测。

  1. 我们将依赖后端的“正确”行为——例如,不会根据以前构建的剩余数据或其他任何内容给出不同的结果。

我很想扩展 PEP-517 以使其成为明确的要求。

我很想扩展 PEP-517 以使其成为明确的要求。

它已经是这样说的:

后端可以在缓存位置或临时目录中存储中间工件。 任何缓存的存在与否不应对构建的最终结果产生重大影响。

不是后端故意违反这个要求,因为用户会很自然地将问题报告为 pip 问题,并被重定向到后端项目,这有点额外的开销。

在尝试为 Fedora 寻找解决方法时,我们遇到了https://github.com/pypa/pip/issues/7872

由于我们已经与#7731 和朋友一起解决了“cwd 中的.egg-info”问题,因此在就地构建时无需担心这一点。

所以选项 4(总是就地构建)在 #7882 中实现。

我们现在(根据 #7951)发布了 pip 的 beta 版本,pip 20.1b1。 此版本包括 #7882,它为此问题实施了解决方案。

我希望这个问题的参与者能够通过测试 Beta 版和检查新错误来帮助我们。 我们希望在周二发布 20.1 主要版本之前确定并解决所有潜在问题。

我也欢迎“是的,现在效果更好了!”的积极反馈。 同样,因为问题跟踪器通常充满了“问题”。 :)

我们完全计划在 Fedora 中对其进行测试(在您发表评论之前我们已经计划好了),但是周二的截止日期可能不现实。

@hroncok知道 Fedora 何时可以测试这些更改吗?

我会尽力在星期一以某种方式做到这一点,但是我不能做出任何承诺。

事实上,20.1b1 使我们的问题消失了。

https://mail.python.org/archives/list/[email protected]/message/5EAUIYYIRKXEHTAG5GQ7EJHSXGZIW2F7/中更一般的20.1b1反馈

欢呼! 非常感谢您试用 Beta @hroncok! 非常感激! ^>^

就地构建的一个结果:我一直在为多个版本的 python 并行构建轮子(在 manylinux docker 容器内)。 对于就地构建,由于不同的版本冲突,并行构建不起作用。 对于树外构建,每个版本都创建了一个单独的树并且没有问题。

@manthey讨论在 #8168 下

所以现在已经10多天了。 有一些关于更改的问题(我都预料到了 - #8165、#8168、#8196)。 还有人明确提到变化正在帮助他们。

  • 除了性能问题之外,之前的行为(复制到临时目录)还有正确性问题(上面链接),如果没有只有调用者拥有的上下文知识,pip 无法修复这些问题(并且,作为旁注,copytree 代码已经充满了应对奇怪情况的创可贴 - 树中的 tmpdir、套接字等)。
  • 激活先前行为的选项仍然存在正确性和性能问题。
  • 一个正确的解决方案将涉及构建后端支持来控制今天并不完全存在的构建目录(例如,setuptools bdist_wheel--bdist-dir ,但仍然写入.egg-info地方,另见 https://github.com/pypa/setuptools/issues/1816、https://github.com/pypa/setuptools/issues/1825)。 因此,既然 pip 行为正确,那么讨论可能会转移到看看,例如,setuptools 是否可以在不接触源目录的情况下演化出进行构建的选项,然后查看是否需要更改 PEP 517 来控制该选项。
  • 与此同时,报告的问题可能相对容易被调用者解决(例如,通过将自己复制到临时目录,或制作临时 tarball,他们可以在完全了解上下文的情况下正确执行这些操作)。
  • 最后,根据我们拥有的数据很难确定,但我的直觉是这种变化对更多人的帮助而不是伤害。

所以我讨厌破坏性的改变,但这个改变不是轻率的,出于这些原因,我个人倾向于保留它。

我不同意新行为是 pip 行为“正确”,肯定会有所不同,并且显然在某些情况下会有所不同,我认为将其构建为这样是不正确的。 它代表了一组损坏用户与一组不同用户的权衡,在这两种情况下,这里都有可以完成的变通方法。

我不会合并这个更改并且错过了它的发生,或者我会反对它(我认为现在已经合并它,它使一些人使用 pip 作为强制功能来帮助防止某些类型的损坏包变得更加困难)。 话虽如此,我真的不知道在这里恢复是否正确。 如果行为反复无常,用户可能会更加困惑。 如果我们要恢复,我们应该尽快做,如果不是,那么当前的行为应该是好是坏。

我使用了“正确”这个词,因为在pip wheel <localdir>pip install <localdir> cd <localdir> ; setup.py bdist_wheel在某些情况下生成与https://github.com/pypa/pip/issues/7555#issuecomment -595180864,或#6276,或普通错误。 我不认为 pip 20.1 会产生如此糟糕的轮子/安装,所以从这个意义上说,我相信它确实更正确。

当然,我们知道更改会破坏一些工作流程,既然我们有反馈,就必须重新评估权衡,并永久恢复或确认。

它仍然可以产生与setup.py sdist && pip install dist/*.tar.gz不同的轮子。

我的建议是恢复 PR 并通过首先通过 sdist 改组然后从结果 sdist 构建轮子来实施修复。

这应该解决所有正确性问题,除非项目无法正确构建 sdist,也就是说,IMO,不是要解决的重要用例。

那里的权衡是它会更慢。 但是,一旦我们实现了它,我们就可以进一步完善 PEP 517 接口,以添加支持加速的可选 API。 这可能永远不会像这种变化那样快,但我们当然可以更接近它。

这种变化使得在不引入用户不太可能满意的性能回归的情况下,实际上不可能进一步推动正确性。 但是,如果我们使其正确,然后提高性能,我们就可以达到双方都满意的中间地带。

正如一句古老的格言所说,首先要做到正确,然后再快速。 我担心通过这个 PR,我们让它变得很快,并锁定了我们使其正确的能力。

我仍然同意验证 sdists 是可取的,但不是在 pip 安装时。 也许这是未来 sdist 构建器工具或 pip build 命令的一个功能。

此外, setup.py sdist在本地目录中创建 .egg-info,因此报告的只读源目录或并发构建问题将保留。

如果它没有在 pip 安装时发生,它在功能上不会发生,直到其他人的 pip 安装时间。 跳过它只是意味着我们有多个路径,一个项目可以继续从 VCS 到已安装的包,每个路径都是另一个差异的机会。 这不是什么新鲜事,基本上我们所有的改变安装路径的选项最终都会在磁盘上得到一组不同的字节,即使对于最严格的项目也是如此。 细微的差异总是存在,你只是希望这些差异没有意义——或者你可以尽你所能消除这些差异,从结构上让它们从一开始就不可能存在。

如果/当通过 sdist 构建时,某些性能问题确实会再次出现,但它们可能比我们在 pip < 20.1 中所遇到的低一个数量级。 实际上,大部分内容通常来自复制.gitvenv或其他不相关的大量内容,这些内容不会出现在 sdist 中。

不管pip最终会得到什么,我们是否可以选择另一个,因为它不可能满足所有人? 我想如果要保留当前的方法(我真的没有意见应该是默认方法),我们应该能够提供最后结果回退,用户可以选择创建一个 sdist 并安装包从那里。

此外, setup.py sdist在本地目录中创建.egg-info ,因此报告的只读源目录或并发构建问题将保留。

我认为(至少一个快速测试与我一致)只有setuptools (不是distutils )这样做,并且这种行为是可配置的,以在其他地方创建目录。 与其他后端类似,我们应该能够推荐它们进行干净的sdist 生成。

FWIW,如果我们采用 generate-sdist-unpack-it-build-wheel 方法,我认为我们不需要将 sdist-generation --egg-info目录转储到工作目录中,因为我们可以将它转储到一个临时目录中,就像我们对generate_metadata所做的那样。

@pradyunsg不需要更改设置工具吗? 上次我检查sdist命令时没有指定.egg-info基本位置的选项,相反egg_info有一个我们利用的--egg-base选项在#7978。

的确! 我在 setuptools 中查看了错误的文件。 🙈 我已经纠正了。

为什么这个空间的一切都如此复杂? :(

$  ls -la
total 8
drwxr-xr-x  3 dstufft  staff   96 May  6 14:26 .
drwxr-xr-x  9 dstufft  staff  288 Apr 28 15:46 ..
-rw-r--r--  1 dstufft  staff   85 Apr 23 16:23 setup.py

$  py setup.py egg_info --egg-base /tmp/foo sdist
/Users/dstufft/.pyenv/versions/3.8.2/lib/python3.8/site-packages/setuptools/dist.py:471: UserWarning: Normalizing '2020.04.23.3' to '2020.4.23.3'
  warnings.warn(
running egg_info
creating /tmp/foo/dstufft.testpkg.egg-info
writing /tmp/foo/dstufft.testpkg.egg-info/PKG-INFO
writing dependency_links to /tmp/foo/dstufft.testpkg.egg-info/dependency_links.txt
writing top-level names to /tmp/foo/dstufft.testpkg.egg-info/top_level.txt
writing manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
reading manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
writing manifest file '/tmp/foo/dstufft.testpkg.egg-info/SOURCES.txt'
running sdist
warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md

running check
warning: Check: missing required meta-data: url

warning: Check: missing meta-data: either (author and author_email) or (maintainer and maintainer_email) must be supplied

creating dstufft.testpkg-2020.4.23.3
copying files to dstufft.testpkg-2020.4.23.3...
copying setup.py -> dstufft.testpkg-2020.4.23.3
Writing dstufft.testpkg-2020.4.23.3/setup.cfg
creating dist
Creating tar archive
removing 'dstufft.testpkg-2020.4.23.3' (and everything under it)

$ ls -la                                        
total 8
drwxr-xr-x  4 dstufft  staff  128 May  6 14:28 .
drwxr-xr-x  9 dstufft  staff  288 Apr 28 15:46 ..
drwxr-xr-x  3 dstufft  staff   96 May  6 14:28 dist
-rw-r--r--  1 dstufft  staff   85 Apr 23 16:23 setup.py

https://github.com/pypa/pip/issues/8165#issuecomment -624669107 这感觉就像一个漂亮的表演停止错误,可以说不是我们的错误,但这是我认为在 PEP 517 讨论期间会发生的一种错误类型默认情况下进行就地构建。

过去曾要求bdist_wheel自动清理其构建目录。 该功能应该进入。其他 distutils 构建干净吗?

如果是 SCons,它会记住它关心的文件,并且会从轮子中忽略 build/ 目录中的额外文件,即使它们存在于文件系统中。

我相信上述问题不仅仅影响 manylinux。 它应该在构建目录不足以捕获 ABI 的任何时候发生(在 setuptools 的情况下,似乎平台和 python 版本是在构建目录中的 ABI 标记中捕获的所有内容)。 我认为这也超出了当前解释器的 ABI,例如,如果某些内容与 NumPy 相关联,我认为它有一个 ABI 可以在较新的但不适用于较旧的 NumPy 上工作,除非他们在构建目录命名中对其进行编码,否则这将效果也是这样使用的。

自动清理构建目录并不能解决问题,它只会降低它的可能性(例如,并行运行两个pip wheel调用仍然可能触发问题),除此之外,这是实现的假设原因之一通过这种方式(至少在 PEP 517 讨论期间),这将通过允许在增量构建的调用之间进行缓存来提供更高的性能。 IOW 当前的行为是某些子集想要的,在运行之间重用构建工件,只是碰巧到目前为止最常见的构建后端得到了非常错误的(并且可以说在某些情况下没有足够的信息来正确无误)包定制)。

当然,对于底层的setuptools命令有足够的标志,你可以解决这个问题(像py setup.py egg_info --egg-base /tmp/foo build --build-base /tmp/foo/build-base bdist_wheel --bdist-dir /tmp/foo/bdist这样的东西可以做到)。

我重申,虽然问题不是额外的文件,而是轮子兼容的预期 ABI 发生了变化,并且.so没有得到重建。 如果 SCons 足够聪明,知道用 pymalloc 构建的 Python 需要一个构建目录,而 Python 用另一个构建目录(包括.so可能链接到的 NumPy 版本之类的东西),那么它不会受到影响。 如果它会使用不同的 ABI 重用以前构建的工件,那么它就会受到影响。

我试图测试 enscons,但我根本无法在没有错误的情况下构建 rsalette。

我试图测试 scikit-build 以查看它如何处理增量构建,无论我做什么,它都会在第二次构建时自行呕吐,我每次都必须手动删除_skbuild目录才能将其恢复运行没有错误。

凉爽的。 很抱歉,enscons 已更新,而 rsalette 尚未更新。

在 2020 年 5 月 6 日星期三下午 4:18,唐纳德·斯塔夫特写道:

我试图测试 enscons,但我根本无法在没有错误的情况下构建 rsalette。

我试图测试 scikit-build 以查看它如何处理增量构建,无论我做什么,它都会在第二次构建时自行呕吐,我每次都必须手动删除_skbuild目录才能将其恢复运行没有错误。


您收到此消息是因为您发表了评论。
直接回复本邮件,在 GitHub 上查看https://github.com/pypa/pip/issues/7555#issuecomment-624867490 ,或者退订https://github.com/notifications/unsubscribe-auth/AABSZERIEDAPUIXCPAKBBUDRQHAXRANCNFSM4KCV5MHQ

很抱歉,enscons 已更新,而 rsalette 尚未更新。

是否有使用更新的 enscons 的好的 C ext? 我刚刚选择了 rsalette,因为它在列表中排在第一位,并且不想调试它,很高兴尝试其他东西。

rsalette的唯一问题是它不应该将ROOT_IS_PURELIB传递给 SConstruct 中的 Environment。 它没有 C 扩展名。 cryptacular看起来不错。

第8165章(评论)

有了这个,我想我同意我们应该恢复这个变化。

我认为新的问题比预期的要大得多。 也许快速恢复 20.1.1,然后我们可以就如何解决树内和树外构建的问题进行更长时间的讨论?

我也投票支持恢复并追求https://discuss.python.org/t/proposal-adding-a-persistent-cache-directory-to-pep-517-hooks/2303/15作为解决方案(这将允许后端不就地构建,因此不会暴露此类问题)。 如果您同意那里的建议,也可以加入该线程。

这对我来说似乎也很明智。 我认为树内(或从 sdist 构建)方法有一些非常显着的好处(我很确定当我们恢复时会收到部分用户群的抱怨🙂)但缺点也是重大。

我不清楚这里的 UI 应该是什么(默认使用哪种方法?我们应该有什么样的选择?)但我确实认为我们应该花更多的时间来决定,而不是在解决当前问题的同时做出决定.

好吧! 我认为普遍的共识是恢复和重新评估。 我会为此提交 PR。 :)

如果您同意那里的建议,也可以加入该线程。

请做 - 我一直在评论,但我已经到了我不知道提供有意义的建议的地步,所以来自有更多经验的人的意见将是有价值的。

刚刚在https://github.com/pypa/pip/issues/8165#issuecomment -625401463 中删除了几个 big-blob-of-text。 我今天要离开了...最后在写个人笔记时我最终感到有点沮丧。 以#5599 结尾并阅读用户的负面评论当然无济于事。

大家好,我对此进行了更多思考,这是我目前对此事的看法。

  1. 就地构建 sdist,将 sdist 解压缩到临时位置,然后从中构建。

我仍然相信 pip install / pip wheel 不是尝试捕获坏 sdists 的正确位置。 这不应该是不首先创建不良 sdists 的后端责任吗? 此外,我认为通过 sdist 的无条件构建可能与就地构建一样具有破坏性。

  1. 添加 pip 选项以就地构建。

我最喜欢短期内的那个,因为解决方案 4 没有成功。 在 pip 20.1.1 中添加它是否为时过早?

  1. 使用某种机制更新 PEP 517,让后端与前端通信,如果它们对于就地构建是“安全的”。

有了这个 pip 仍然需要回到其损坏且无法修复的 copytree,所以我不赞成这个。

  1. 将 pip 更改为始终就地构建。

所以这个被认为太具有破坏性,我们将在 20.1.1 中恢复。

  1. 默认情况下将 pip 更改为就地构建,并带有构建树外的选项。

这可能是长期目标,即构建与缓存目录概念混合的树外选项?

我真的不喜欢 CLI 选项,尤其是像这样的选项。 如果我列出了本地 FS 上的两个包,而我需要构建一个就地构建一个不需要,该怎么办? 如果我们提供一个选项来做一个或另一个,那么现有的包最终只能用一个或另一个来构建。

对我来说,它也像那种完全因为项目无法做出决定而存在的选项,并决定将这个决定推给最终用户。

通过 sdist 构建并不完全是为了捕捉坏的 sdist。 在很大程度上,它是关于减少项目在最终安装之前可能经历的“路径”的可能变化。 以某种方式添加标志会使问题变得更糟而不是更好。

对于我的意思,我们有一些安装可以通过的“路径”:

  1. VCS -> Sdist -> Wheel -> Installed
  2. VCS -> 车轮 -> 已安装
  3. VCS -> 已安装(旧版)

还有一些正在逐步淘汰的其他路径,但总的来说,这些是我们的 3 个(理想情况下 3 个也被淘汰了)。 还有可编辑的安装,但它们不会很快消失。

我们可以考虑将 sdist 或轮子上传到 PyPI 并从中安装到同一“路径”的一部分,您只需暂停它并在另一台计算机上完成它。

像这样有多个“路径”的问题是它在最终安装的结果中引入了不一致。 它们并不总是发生,但它经常发生是一个很容易观察到的情况。 很多时候,这些不一致没什么大不了的,但有时确实如此。

如果我们做这样的就地构建,那么我们实际上是在说我们永远无法折叠成一条路径,而且我们总是不得不处理这种奇怪的边缘情况,有时人们会根据安装的方式得到不同的结果。

作为一个额外的好处,这也可以作为一个强制函数来帮助确保快乐路径保持快乐。

大多数情况下,我同意@dstufft ,特别是我同意 build-from-sdist 方法不应被视为“试图验证 sdists”,而是“一切都遵循”源树 -> sdist -> wheel -> 安装路线(只是有些事情跳过了一些初始步骤)”。

但是,我确实想指出一点:

如果我列出了本地 FS 上的两个包,而我需要构建一个就地构建一个不需要,该怎么办?

只需在具有不同选项的两次单独运行的 pip 中运行这两个包?!? 我知道有可能一个是另一个的依赖,你的观点通常是成立的,但人们似乎普遍倾向于假设每个安装场景都必须折叠成一个 pip 运行,而我不不认为这是合理的(对于被用户拒绝的问题,我们有非常好的解决方法,因为“这意味着我必须将我的需求列表一分为二”)

请注意,当(如果)我们恢复时,我们需要重新打开像 #6276 这样的问题,该问题由于实施树内构建而关闭。

部分问题是 pip 在解析依赖项时不考虑已安装的内容(我不确定新的解析器工作是否会改变它?)依赖关系“正确”(就我们当前的解析器正确执行任何操作而言)。

如果新的解析器考虑到已经安装的内容,那么pip install foo barpip install foo && pip install bar将大致相等,根本不重要,但如果不是(现在大致相同)如果两个项目都依赖于“垃圾邮件”,但 foo required < 2 和 bar required > 1 那么我们会得到一个无效的安装。

虽然这是一个切线:)

(我不确定新的解析器工作是否会改变?)

欢迎在#7744 上输入。 :)

  1. 将 pip 更改为始终就地构建。

所以这个被认为太具有破坏性,我们将在 20.1.1 中恢复。

需要明确的是,这也是我们“推出得太快”的原因,而我们采取的推出方法绝对是这最终造成破坏性太大的部分原因。

  1. 添加 pip 选项以就地构建。

@dstufft @pfmoore我认为这种选项是一种选择加入机制,因此我们可以逐步将用户推向就地构建,目标是在某个时候将其设为默认设置。 本着评论的精神: https :

我会为此提交 PR。 :)

8221它是。

20.1.1 已发布,包含已恢复的更改。

在 Fedora 中,当我们构建 Python RPM 包时,我们就像恐龙一样,进行瘦身的标准方法是使用python setup.py build 。 在 PEP 517 中,我们添加了一种使用pip wheel的“临时”方式。 但是,对于扩展模块,我们遇到了 pip 用于构建它们的“将源移动到 tmp,从那里构建”方法的问题。

我们的构建机制正在注入一些编译器标志,因此构建工件(在本例中.so扩展模块)包含有关其源的元数据。 后来有一个 shell 脚本,它遍历构建工件,提取此信息并将源复制到/usr/src/debug以通过特殊的*-debugsource RPM 进行安装。 机械厂希望一切都在工作树中构建,而在外部构建时它并不能很好地工作。 以下是可以(一起)做的事情来缓解我们这边的问题:

1. set the `$TMPDIR` environment variable to have it within the place where the RPM script expects it (i.e. `export TMPDIR=%{_builddir}/.tmp` (and create it))

2. use `pip wheel` with the `--no-clean` option to keep the copied sources in `$TMPDIR`

3. run some shell kung fu to rewrite the "what is my source" information to the correct location: `find %{buildroot} -iname '*.so' -print0 | xargs --no-run-if-empty -0 -n1 /usr/lib/rpm/debugedit -b "%{_builddir}/.tmp/pip-req-build-"* -d "$PWD"`

4. (Optional: clean `$TMPDIR` manually.)

这实际上是我在查看 pip 集成、#6505 等时开始的路径。

今天使用 pip 的迭代构建被有效地破坏了,这对于拥有大量 C 扩展形式的 python 代码的组来说是一个重大损失,因此我诉诸于使用setup.py调用构建。

pip需要build命令并且build命令的最终结果应该可以传递给其他子命令,例如wheelinstall , 等等。

现在pip有效地将install视为buildinstall ,这_不是_一些正在构建和缓存二进制工件、安装二进制文件的人想要的- 仅坐骑等

我真的希望有使用方式setup.py打造的二进制文件,然后pip install他们而不是诉诸创建bdist ,但似乎并没有在今天成为可能,因为pipdistutils / setuptools不同意在哪里可以找到二进制工件。

我真的希望有一种方法可以使用 setup.py 来构建二进制文件,然后 pip 安装它们而无需创建 bdist,但今天似乎不可能,因为 pip 和 distutils/setuptools 不同意在哪里可以找到二进制工件。

我不确定我是否遵循 - 您是说您想要一种使用二进制文件的方法,但不想使用已经存在的二进制分发格式。 这是为什么?

我真的希望有一种方法可以使用 setup.py 来构建二进制文件,然后 pip 安装它们而无需创建 bdist,但今天似乎不可能,因为 pip 和 distutils/setuptools 不同意在哪里可以找到二进制工件。

我不确定我是否遵循 - 您是说您想要一种使用二进制文件的方法,但不想使用已经存在的二进制分发格式。 这是为什么?

bdist 格式非常有限。 我的团队不得不求助于一种愚蠢的格式,比如 tar,然后逐字解压缩(不支持任何 BSD,不支持 Debian 等)。

我昨晚发现使用愚蠢的 bdist 不能通过pip 。 愚蠢的二进制文件缺少需要通过pip安装的元数据,AFAICT,我猜这就是 pip 轮子发挥作用的地方。

我也尝试过 egg 和 zip,但它们缺少仅使用file:// URI 进行安装所需的元数据。

我一直在尝试通过 distutils、setuptools 将构建硬塞进一个更大的构建系统中,使用 make,所以我无法说明我是否已经完成了“所有正确的事情”来使事情按照标准bdist的方式工作

来自https://github.com/pypa/pip/issues/2195#issuecomment -664728481 我可以说我很高兴在--use-feature=in-tree-build后面重新做#7882。

欢呼! 听起来像是个计划!

这次我们也更新--build的文档字符串。 ;)

来自#2195(评论),我可以说我很高兴在--use-feature=in-tree-build 后面重新做#7882。

好奇它是否以及通过命令行在pyproject.toml设置in-tree-build选项是否合理? 这对于解决 #6276 非常好,而无需制作 bash 脚本或 makefile 来包装 pip。 (并不是说这是一个特别大的问题。)

在 pyproject.toml 中设置了 in-tree-build 选项

@davidhewitt在此问题的原始描述中,这或多或少是选项 3。 我的理解是,目前的共识是,如果可以,最好避免额外的选择。 因此,在过渡期间使用--use-feature启用树内构建的想法,其长期目标是使其成为默认和唯一机制。

顺便说一句,我将无法在 20.3 中及时实现这一点,但我仍然打算这样做,希望在 20.4 中实现。

@sbidoul我写了一个补丁来帮助获得这个功能 - 见 #9091。

此页面是否有帮助?
0 / 5 - 0 等级