source()¶
source()
方法可以用于检索从源代码构建包所需的源代码,并在必要时对这些源代码应用补丁。当一个包正在从源代码构建时,例如使用 conan create
或 conan install --build=pkg*
,它会被调用,但如果正在使用预编译的二进制包,则不会被调用。这意味着如果存在预编译的二进制文件,则不会下载源代码。
source()
方法可以实现不同的策略来检索源代码
获取第三方库的源代码
使用
Git(self).clone()
克隆 Git 仓库执行
download()
+unzip()
或组合的get()
(内部执行下载 + 解压) 来下载 tarball、tgz 或 zip 压缩包。
从其仓库中获取自身的源代码,其坐标已在
export()
方法中的conandata.yml
文件中捕获。这是用于管理包源代码的策略,其中conanfile.py
位于包本身中,但由于某些原因我们不想将源代码放入 recipe 中(例如不分发我们的源代码,但能够分发我们的包二进制文件)。
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()
方法中引入条件语句。如果补丁以文件形式存在,则必须将这些补丁与 recipe 一起导出,以便在任何时候从源代码构建时都可以使用它们。
可以使用以下方法应用补丁:
您自己的或
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()
方法中有条件地检索该代码。
强制检索源代码¶
当在用户文件夹中使用 recipe 时,很容易调用 source()
方法并强制检索源代码,这将在同一用户文件夹中根据 layout()
定义完成
$ conan source .
即使某些依赖项不是从源代码构建的,也可以通过 tools.build:download_source=True
配置在缓存中调用 source()
方法并强制检索源代码,对于所有或某些依赖项。例如
$ conan graph info . -c tools.build:download_source=True
将计算依赖关系图,然后为图中所有 “host” 包调用 source()
方法(由于默认配置是 “host” 配置,如果您还想要 “build” 上下文 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
对 editable 模式下的包没有任何影响。在这种情况下下载源代码很容易覆盖和破坏开发人员对该代码的本地更改。必须在 editable 模式下的包上使用 conan source
命令来下载源代码。
注意
最佳实践
source()
方法对于所有配置都应该是相同的,它不能依赖于任何配置条件。source()
方法应该检索不可变的源代码。使用某些分支名称、HEAD 或 URL 不是不可变的并且正在被覆盖的 tarball 是一种不良做法,并且会导致包损坏。使用 Git 提交、冻结的 Git 发布标签或固定的和版本化的发布 tarball 是预期的输入。默认情况下,应该在
source()
方法中应用补丁,除非补丁是某个配置独有的,在这种情况下,它们可以在build()
方法中应用。source()
方法不应访问或操作与self.source_folder
不同的其他文件夹中的文件。所有 “exported” 文件在调用它之前都会复制到self.source_folder
。
另请参阅
有关更多信息,请参阅 关于管理 recipe 源代码的教程。