准备构建¶
在上一教程部分中,我们将 fmt 依赖项添加到我们的 Conan 包中,为我们的“Hello World” C++ 库提供彩色输出。在本节中,我们将重点介绍配方中的 generate()
方法。此方法旨在生成在运行构建步骤时可能需要的所有信息。这意味着诸如
为构建步骤编写文件,例如注入环境变量的脚本、要传递给构建系统的文件等。
配置工具链以提供基于设置和选项的额外信息,或移除 Conan 默认生成的、可能不适用于某些情况的工具链信息。
我们解释如何基于上一教程部分使用此方法进行一个简单的示例。我们在配方中添加了一个 with_fmt 选项,根据其值,我们或不或地要求 fmt 库。我们使用 generate()
方法修改工具链,以便将变量传递给 CMake,从而我们可以有条件地添加该库并在源代码中使用 fmt 或不使用。
请先克隆源代码以重新创建此项目。您可以在 GitHub 上的examples2 仓库中找到它们。
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/creating_packages/preparing_the_build
您会注意到 conanfile.py 文件与之前的配方有一些不同。让我们看看相关的部分。
...
from conan.tools.build import check_max_cppstd, check_min_cppstd
...
class helloRecipe(ConanFile):
name = "hello"
version = "1.0"
...
options = {"shared": [True, False],
"fPIC": [True, False],
"with_fmt": [True, False]}
default_options = {"shared": False,
"fPIC": True,
"with_fmt": True}
...
def validate(self):
if self.options.with_fmt:
check_min_cppstd(self, "11")
check_max_cppstd(self, "14")
def source(self):
git = Git(self)
git.clone(url="https://github.com/conan-io/libhello.git", target=".")
# Please, be aware that using the head of the branch instead of an immutable tag
# or commit is not a good practice in general
git.checkout("optional_fmt")
def requirements(self):
if self.options.with_fmt:
self.requires("fmt/8.1.1")
def generate(self):
tc = CMakeToolchain(self)
if self.options.with_fmt:
tc.variables["WITH_FMT"] = True
tc.generate()
...
正如您所见
我们声明了一个新的
with_fmt
选项,默认值为True
。根据
with_fmt
选项的值我们有条件地安装
fmt/8.1.1
Conan 包。我们有条件地要求最低和最高 C++ 标准,因为 _fmt_ 库至少需要 C++11,如果我们尝试使用高于 C++14 的标准(这只是一个示例,_fmt_ 实际上可以支持更现代的标准)它将无法编译。
我们将
WITH_FMT
变量及其值True
有条件地注入到 CMakeToolchain 中,以便我们可以在 hello 库的 _CMakeLists.txt_ 中使用它来添加 CMake fmt::fmt 目标。
我们正在克隆该库的另一个分支。_optional_fmt_ 分支包含一些代码更改。让我们看看 CMake 方面发生了什么变化。
cmake_minimum_required(VERSION 3.15)
project(hello CXX)
add_library(hello src/hello.cpp)
target_include_directories(hello PUBLIC include)
set_target_properties(hello PROPERTIES PUBLIC_HEADER "include/hello.h")
if (WITH_FMT)
find_package(fmt)
target_link_libraries(hello fmt::fmt)
target_compile_definitions(hello PRIVATE USING_FMT=1)
endif()
install(TARGETS hello)
正如您所见,我们使用了在 CMakeToolchain 中注入的 WITH_FMT
。根据其值,我们将尝试查找 fmt 库并将其链接到我们的 hello 库。另外,请注意我们添加了 USING_FMT=1
编译定义,我们在源代码中使用它,这取决于我们是否选择添加对 fmt
的支持。
#include <iostream>
#include "hello.h"
#if USING_FMT == 1
#include <fmt/color.h>
#endif
void hello(){
#if USING_FMT == 1
#ifdef NDEBUG
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "hello/1.0: Hello World Release! (with color!)\n");
#else
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "hello/1.0: Hello World Debug! (with color!)\n");
#endif
#else
#ifdef NDEBUG
std::cout << "hello/1.0: Hello World Release! (without color)" << std::endl;
#else
std::cout << "hello/1.0: Hello World Debug! (without color)" << std::endl;
#endif
#endif
}
让我们先使用 with_fmt=True
从源代码构建包,然后再使用 with_fmt=False
。当 _test_package_ 运行时,它将根据选项的值显示不同的消息。
$ conan create . --build=missing -o with_fmt=True
-------- Exporting the recipe ----------
...
-------- Testing the package: Running test() ----------
hello/1.0 (test package): Running test()
hello/1.0 (test package): RUN: ./example
hello/1.0: Hello World Release! (with color!)
$ conan create . --build=missing -o with_fmt=False
-------- Exporting the recipe ----------
...
-------- Testing the package: Running test() ----------
hello/1.0 (test package): Running test()
hello/1.0 (test package): RUN: ./example
hello/1.0: Hello World Release! (without color)
这只是一个如何使用 generate()
方法根据一个选项的值自定义工具链的简单示例,但您还可以在 generate()
方法中执行许多其他操作,例如:
创建基于您需求的完整自定义工具链以在您的构建中使用。
访问有关包依赖项的某些信息,例如:
使用 Environment tools 为系统环境生成信息。
添加自定义配置(除了 _Release_ 和 _Debug_),同时考虑设置,例如 _ReleaseShared_ 或 _DebugShared_。
另请参阅
使用
generate()
方法 从依赖项导入文件。