source()

source() 方法可用于检索用于从源代码构建包的必要源代码,并在必要时对这些源代码应用补丁。当从源代码构建包时(例如使用 conan createconan install --build=pkg*),将调用此方法,但如果正在使用预编译的二进制包,则不会调用。这意味着如果存在预编译的二进制文件,则不会下载源代码。

source() 方法可以实现不同的检索源代码的策略

  • 获取第三方库的源代码

    • 使用 Git(self).clone() 克隆 Git 仓库

    • 执行 download() + unzip() 或组合的 get()(内部执行下载 + 解压)来下载 tarball、tgz 或 zip 存档。

  • 获取自身的源代码,从其仓库获取,该仓库的坐标已在 export() 方法的 conandata.yml 文件中捕获。这是用于管理包源代码的策略,其中 conanfile.py 存在于包本身中,但出于某些原因我们不想将源代码放入配方中(例如,不分发我们的源代码,但能够分发我们的包二进制文件)。

source() 方法在 self.source_folder 中执行,当前工作目录将等于该文件夹(其值源自 layout() 方法)。

source() 实现可能会使用方便的 get() 辅助函数,或者使用自己的机制或其他 Conan 辅助函数来完成此任务,例如

import os
import shutil

from conan import ConanFile
from conan.tools.files import download, unzip, check_sha1


class PocoConan(ConanFile):
    name = "poco"
    version = "1.6.0"

    def source(self):
        zip_name = f"poco-{self.version}-release.zip"
        # Immutable source .zip
        download(self, f"https://github.com/pocoproject/poco/archive/poco-{self.version}-release.zip", zip_name)
        # Recommended practice, always check hashes of downloaded files
        check_sha1(self, zip_name, "8d87812ce591ced8ce3a022beec1df1c8b2fac87")
        unzip(self, zip_name)
        shutil.move(f"poco-poco-{self.version}-release", "poco")
        os.unlink(zip_name)

重要

请阅读 conan.tools.files.unzip() 中关于 Python 3.14 破坏性变更和新的 tar 存档提取过滤器注意事项。

如果补丁适用于所有可能的配置,则可以在 source() 方法中应用(也应该在此处应用)补丁。如上所述,无法在 source() 方法中引入条件。如果补丁以文件形式存在,则必须与配方一起导出这些补丁,以便在触发从源代码构建时可以使用它们。

可以使用以下方式应用补丁:

  • 您自己的或 git 补丁工具

  • Conan 内置的 patch() 工具,用于显式地逐个应用补丁

  • 应用 apply_conandata_patches() Conan 工具,以按照某些约定自动应用 conandata.yml 文件中定义的所有补丁。

源代码缓存

调用 source() 方法后,其结果将被缓存并重复用于任何从源代码进行的构建,无论是什么配置。这意味着从 source() 方法检索源代码应完全独立于配置。无法在 settings 中实现条件,并且通常,任何尝试将条件逻辑应用于 source() 方法的做法都是错误的。

def source(self):
    if self.settings.compiler == "gcc":  # ERROR, will raise
        # download some source

尝试使用其他机制绕过 Conan 异常,例如

def source(self):
    # Might work, but NOT recommended, try to avoid as much as possible
    if platform.system() == "Windows":
        # download something
    else:
        # download something different

在不进行任何交叉构建且不在不同操作系统中重新收集源代码的情况下,可能表面上看起来有效,但否则可能会有问题。

为确保安全,如果不同配置需要不同的源代码,推荐的方法是在 build() 方法中以条件方式检索该代码。

强制检索源代码

在用户文件夹中处理配方时,可以轻松调用 source() 方法并强制检索源代码,这将在此用户文件夹中进行,具体取决于 layout() 定义。

$ conan source .

通过 tools.build:download_source=True 配置,可以调用 source() 方法并强制在缓存中检索所有或部分依赖项的源代码,即使它们不从源代码构建。例如

$ conan graph info . -c tools.build:download_source=True

将计算依赖关系图,然后为图中的所有“主机”包调用 source() 方法(因为配置默认是“主机”配置;如果您也想要“构建”上下文的 tool_requires 的源代码,可以使用 -c:b tools.build:download_source=True)。可以通过 JSON 格式的输出收集所有源代码文件夹,或者自动化源代码的收集,可以使用 deployer

同样,通过传递配置,可以为其他 createinstall 命令中的包检索源代码。最后,由于配置也可以按包定义,使用 -c mypkg*:tools.build:download_source=True 将只检索匹配 mypkg* 模式的包的源代码。

请注意,tools.build:download_source=True可编辑模式下的包没有影响。在这种情况下下载源代码很容易覆盖和破坏对该代码的本地开发人员更改。必须在可编辑模式下的包上使用 conan source 命令来下载源代码。

注意

最佳实践

  • source() 方法对于所有配置都应该是相同的,它不能有条件地依赖于任何配置。

  • source() 方法应检索不可变源代码。使用分支名称、HEAD 或 URL 非不可变且正在被覆盖的 tarball 是不良做法,将导致包损坏。使用 Git commit、冻结的 Git 发布标签或固定的版本化发布 tarball 是预期的输入。

  • 补丁默认应在 source() 方法中应用,除非补丁是仅针对一个配置的,在这种情况下,可以在 build() 方法中应用。

  • source() 方法不应访问或操作 self.source_folder 以外的任何文件夹中的文件。所有“导出的”文件在调用它之前都会被复制到 self.source_folder

另请参阅

有关更多信息,请参阅 管理配方源代码的教程