source()¶
source()
方法可用于检索从源代码构建包所需的源代码,并在必要时对该源代码应用补丁。当从源代码构建包时,它将被调用,例如使用 conan create
或 conan 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()
工具,用于显式逐个应用补丁使用 Conan 工具
apply_conandata_patches()
,根据某些约定自动应用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 .
调用 source()
方法并强制在缓存中检索所有或部分依赖项的源代码,即使它们不是从源代码构建的,也是可能的,通过使用 tools.build:download_source=True
配置。例如
$ conan graph info . -c tools.build:download_source=True
将计算依赖项图,然后为图中所有“主机”包调用 source()
方法(因为默认配置是“主机”配置,如果您还想要“构建”上下文 tool_requires
的源代码,您可以使用 -c:b tools.build:download_source=True
)。可以从 JSON 格式的输出中收集所有源文件夹,或者自动化重新收集所有源,可以使用 deployer
。
同样,可以通过传递配置来检索其他 create
和 install
命令中包的源代码。最后,由于配置也可以按包定义,使用 -c mypkg*:tools.build:download_source=True
将只检索匹配 mypkg*
模式的包的源代码。
请注意,tools.build:download_source=True
对**可编辑**模式下的包无效。在这种情况下下载源代码很容易覆盖并破坏该代码上的本地开发人员更改。必须在可编辑模式下的包上使用 conan source
命令来下载源代码。
注意
最佳实践
source()
方法应对所有配置都相同,它不能被配置条件化。source()
方法应检索不可变的源代码。使用某个分支名称、HEAD 或不是不可变的且正在被覆盖的 tarball URL 是不好的做法,会导致包损坏。使用 Git commit、冻结的 Git release tag 或固定的、版本化的 release tarball 是预期输入。补丁应用默认应在
source()
方法中完成,除非补丁是针对某个特定配置的,在这种情况下,它们可以在build()
方法中应用。source()
方法不应访问或操作self.source_folder
以外的任何文件夹。所有“导出的”文件在调用source()
方法之前都会被复制到self.source_folder
。
另请参阅
有关更多信息,请参阅 关于管理配方源代码的教程。