本文是基于对conan官方文档source(),build(),package()翻译而来, 更详细的信息可以去查阅conan官方文档。
Method used to retrieve the source code from any other external origin like github using $ git clone
or just a regular download.
用于从其他外部来源获取源代码的方法,例如使用 $ git clone
从 github 获取源代码,或直接下载。
For example, “exporting” the source code files, together with the conanfile.py file, can be handy if the source code is not under version control. But if the source code is available in a repository, you can directly get it from there:
例如,如果源代码不在版本控制之下,"exporting "源代码文件和 conanfile.py
文件会很方便。但如果源代码在版本控制库中,则可以直接从版本控制库中获取:
from conans import ConanFile
class HelloConan(ConanFile):
name = "hello"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
def source(self):
self.run("git clone https://github.com/conan-io/hello.git")
# You can also change branch, commit or whatever
# self.run("cd hello && git checkout 2fe5...")
#
# Or using the Git class:
# git = tools.Git(folder="hello")
# git.clone("https://github.com/conan-io/hello.git")
The current working directory where the source()
method runs is the self.source_folder
. Note, however, that this folder can be different if the recipe defines the layout()
method and specifies a self.folders.source = "src"
. In that case, the self.source_folder
and the current working directory will be the composition of the base folder (typically where the recipe is) and the user specified "src"
subfolder.
运行 source()
方法的当前工作目录是 self.source_folder
文件夹。但请注意,如果配方定义了 layout()
方法并指定了 self.folders.source = "src"
,则该文件夹可以不同。在这种情况下,self.source_folder
和当前工作目录将由基本文件夹(通常是配方所在的文件夹)和用户指定的"src"
子文件夹组成。
This will work, as long as git is in your current path (so in Win you probably want to run things in msysgit, cmder, etc). You can also use another VCS or direct download/unzip. For that purpose, we have provided some helpers, but you can use your own code or origin as well. This is a snippet of the conanfile of the Poco library:
只要 git 在您的当前路径中(因此在 Win 中,您可能希望在 msysgit、cmder 等中运行),这样就可以了。您也可以使用其他 VCS 或直接下载/解压。为此,我们提供了一些辅助工具,但你也可以使用自己的代码或源代码。这是 Poco 库的 conanfile 片段:
from conans import ConanFile
from conans.tools import download, unzip, check_md5, check_sha1, check_sha256
import os
import shutil
class PocoConan(ConanFile):
name = "poco"
version = "1.6.0"
def source(self):
zip_name = "poco-1.6.0-release.zip"
download("https://github.com/pocoproject/poco/archive/poco-1.6.0-release.zip", zip_name)
# check_md5(zip_name, "51e11f2c02a36689d6ed655b6fff9ec9")
# check_sha1(zip_name, "8d87812ce591ced8ce3a022beec1df1c8b2fac87")
# check_sha256(zip_name, "653f983c30974d292de58444626884bee84a2731989ff5a336b93a0fef168d79")
unzip(zip_name)
shutil.move("poco-poco-1.6.0-release", "poco")
os.unlink(zip_name)
The download, unzip utilities can be imported from conan, but you can also use your own code here to retrieve source code from any origin. You can even create packages for pre-compiled libraries you already have, even if you don’t have the source code. You can download the binaries, skip the build()
method and define your package()
and package_info()
accordingly.
下载和解压缩工具可以从 Conan 中导入,但也可以使用自己的代码从任何来源获取源代码。即使没有源代码,你也可以为已有的预编译库创建软件包。你可以下载二进制文件,跳过build()
方法,并相应地定义你的package()
和package_info()
。
You can also use check_md5()
, check_sha1()
and check_sha256()
from the tools module to verify that a package is downloaded correctly.
您还可以使用工具模块中的 check_md5()
、check_sha1()
和 check_sha256()
,验证软件包是否已正确下载。
It is very important to recall that the source()
method will be executed just once, and the source code will be shared for all the package builds. So it is not a good idea to conditionally use settings or options to make changes or patches on the source code. Maybe the only setting that makes sense is the OS self.settings.os
, if not doing cross-building, for example to retrieve different sources:
请记住,source()
方法只执行一次,源代码将在所有软件包的构建过程中共享,这一点非常重要。因此,有条件地使用设置或选项对源代码进行修改或打补丁并不是一个好主意。如果不进行交叉编译,例如检索不同的源代码,也许唯一有意义的设置就是操作系统的 self.settings.os
:
def source(self):
if platform.system() == "Windows":
# download some Win source zip
else:
# download sources from Nix systems in a tgz
If you need to patch the source code or build scripts differently for different variants of your packages, you can do it in the build()
method, which uses a different folder and source code copy for each variant.
如果需要为软件包的不同变体打上不同的源代码补丁或构建脚本,可以在 build()
方法中进行,该方法会为每个变体使用不同的文件夹和源代码副本。
def build(self):
tools.patch(patch_file="0001-fix.patch")
This method is used to build the source code of the recipe using the desired commands. You can use your command line tools to invoke your build system or any of the build helpers provided with Conan.
此方法用于使用所需的命令构建配方的源代码。您可以使用命令行工具调用您的构建系统或 Conan 提供的任何构建助手。
def build(self):
cmake = CMake(self)
self.run("cmake . %s" % (cmake.command_line))
self.run("cmake --build . %s" % cmake.build_config)
You can use these classes to prepare your build system’s command invocation:
您可以使用这些类来准备构建系统的命令调用:
MSBuild()
. For lower level control, the VisualStudioBuildEnvironment can also be used: VisualStudioBuildEnvironment.MSBuild()
这个辅助工具。对于较低级别的控制,也可以使用 VisualStudioBuildEnvironment: VisualStudioBuildEnvironment.We have seen how to run package tests with conan, but what if we want to run full unit tests on our library before packaging, so that they are run for every build configuration? Nothing special is required here. We can just launch the tests from the last command in our build()
method:
我们已经了解了如何使用 conan 运行打包测试,但如果我们想在打包之前对库运行完整的单元测试,以便在每次构建配置时都运行这些测试,该怎么办呢?这里不需要什么特别的东西。我们只需在 build()
方法的最后一条命令中启动测试即可:
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
# here you can run CTest, launch your binaries, etc
cmake.test()
The actual creation of the package, once that it is built, is done in the package()
method. Using the self.copy()
method, artifacts are copied from the build folder to the package folder.
软件包构建完成后,软件包的实际创建将在 package()
方法中完成。使用 self.copy()
方法,工件会从构建文件夹复制到package文件夹。
The syntax of self.copy
inside package()
is as follows:
package()
中的 self.copy
语法如下:
self.copy(pattern, dst="", src="", keep_path=True, symlinks=None, excludes=None, ignore_case=True)
Returns: A list with absolute paths of the files copied in the destination folder.
返回值 包含目标文件夹中已复制文件绝对路径的列表。
Parameters:
*.lib
or *.h
.*.lib
或 *.h
。""
): The folder where you want to search the files in the build folder. If you know that your libraries when you build your package will be in build/lib
, you will typically use build/lib
in this parameter. Leaving it empty means the root build folder in local cache.""
): 您要在联编文件夹中搜索文件的文件夹。如果你知道在构建软件包时你的库将在 build/lib
中,通常会在此参数中使用 build/lib
。留空表示使用本地缓存中的根编译文件夹。""
): Destination folder in the package. They will typically be include
for headers, lib
for libraries and so on, though you can use any convention you like. Leaving it empty means the root package folder in local cache.""
): 软件包中的目标文件夹。通常情况下,头文件文件夹为 include
,库文件夹为 lib
,等等,但也可以使用任何你喜欢的约定。留空表示本地缓存中的软件包根文件夹。True
): Means if you want to keep the relative path when you copy the files from the src folder to the dst one. Typically headers are packaged with relative path.True
to activate symlink copying, like typical lib.so->lib.so.9
.True
可激活符号软连接复制,如典型的 lib.so->lib.so.9
。None
): Single pattern or a tuple of patterns to be excluded from the copy. If a file matches both the include and the exclude pattern, it will be excluded.“None”
):要从副本中排除的单个模式或模式元组。如果一个文件同时匹配包含和排除模式,它将被排除。True
): 如果启用,将进行不区分大小写的模式匹配。For example:
例如:
self.copy("*.h", "include", "build/include") #keep_path default is True
The final path in the package will be: include/mylib/path/header.h
, and as the include is usually added to the path, the includes will be in the form: #include "mylib/path/header.h"
which is something desired.
软件包的最终路径将是 include/mylib/path/header.h
,而由于 include
通常会添加到路径中,因此 includes 的形式将是 "#include “mylib/path/header.h”: 由于 include 通常会添加到路径中,因此包含的形式将是:#include "mylib/path/header.h"
,这也是我们所希望的。
keep_path=False
is something typically desired for libraries, both static and dynamic. Some compilers as MSVC, put them in paths as Debug/x64/MyLib/Mylib.lib
. Using this option, we could write:
keep_path=False
通常是静态和动态库所需要的。有些编译器(如 MSVC)会将它们放在 Debug/x64/MyLib/Mylib.lib
这样的路径下。使用该选项,我们可以编写。
self.copy("*.lib", "lib", "", keep_path=False)
And it will copy the lib to the package folder lib/Mylib.lib
, which can be linked easily.
它将把库复制到软件包文件夹 lib/Mylib.lib
,这样就可以轻松链接。
If you are using CMake and you have an install target defined in your CMakeLists.txt, you might be able to reuse it for this package()
method. Please check How to reuse cmake install for package()
method.
如果您使用的是 CMake,并且在 CMakeLists.txt 中定义了安装目标,您或许可以将其用于此 package()
方法。请查看 如何为 package()
方法重用 cmake install。
This method copies files from build/source
folder to the package
folder depending on two situations:
这种方法会根据两种情况将文件从 build/source
文件夹复制到 package
文件夹:
Build folder and source folder are the same: Normally during conan create
source folder content is copied to the build folder. In this situation src
parameter of self.copy()
will be relative to the build folder in the local cache.
构建文件夹和源代码文件夹是相同的: 通常在conan create
时,源文件夹的内容会被复制到联编文件夹。在这种情况下,self.copy()
的src
参数将相对于本地缓存中的联编文件夹。
Build folder is different from source folder
: When developing a package recipe and source and build folder are different (conan package . --source-folder=source --build-folder=build
) or when no_copy_source is defined, every self.copy()
is internally called twice: One will copy from the source folder (src
parameter of self.copy()
will point to the source folder), and the other will copy from the build folder (src parameter of self.copy() will point to the build folder).
编译文件夹与源代码文件夹不同: 当 developing a package recipe 源文件夹和构建文件夹不同(conan package . --source-folder=source --build-folder=build
)或定义了 no_copy_source 时,每个 self.copy()
都会被内部调用两次:一次是从源文件夹复制(self.copy()
的 src
参数将指向源文件夹),另一次是从构建文件夹复制(`self.copy() 的 src 参数将指向构建文件夹)。