孵化功能¶
本节专门介绍正在开发中的新功能,旨在寻求用户测试和反馈。它们通常位于标志之后,需要显式选择加入此测试阶段。它们需要最新的 Conan 版本(有时建议从 develop2
源代码分支运行),并显式设置这些标志。
新的 CMakeConfigDeps 生成器¶
此生成器旨在替代当前的 CMakeDeps
生成器,它有多个待处理的修复和改进,这些修复和改进在当前生成器中不容易完成,而且不会破坏现有功能
创建真实的 SHARED/STATIC/INTERFACE IMPORTED 目标,不再有人工接口目标。
CONAN_LIB::
和其他类似目标不再存在。为目标定义 IMPORTED_CONFIGURATIONS。
依赖项的 CONFIG 定义与依赖项的
Release/Debug/etc
build_type
匹配,不再使用消费者的配置。定义库目标的 IMPORTED_LOCATION 和 IMPORTED_IMPLIB。
基于 recipe
languages
和cpp_info/component
languages
属性定义 LINK_LANGUAGES。所有这些都允许更好地传播链接需求和可见性,从而避免 Linux 中传递共享库的一些链接错误。
更好地定义包内组件之间以及与其他包相关的
requires
关系。它不需要任何
build_context_activated
或build_context_suffix
来使用tool_requires
依赖项。定义
cpp_info/component.exe
信息(应包括.location
定义),以定义可以运行的 EXECUTABLE 目标。来自
requires
的可执行文件也可以在非交叉构建场景中使用。当存在到同一依赖项的tool_requires
时,这些可执行文件将具有优先级。创建一个新的
conan_cmakedeps_paths.cmake
,其中包含用于直接查找依赖项的<pkg>_DIR
路径的定义。此文件还计划在cmake-conan
中使用,以扩展其用途并避免当前由于 CMake 驱动的安装无法稍后注入工具链而导致的一些限制。
注意
此生成器仅旨在生成 config.cmake
配置文件,它不会生成 Find*.cmake
查找模块,并且不计划支持它。为此,请使用 CMakeDeps
生成器。
除了 CppInfo 中已定义的字段外,还可以在 cpp_info
或 cpp_info.components
中定义的新字段是
# EXPERIMENTAL FIELDS, used exclusively by new CMakeConfigDeps (-c tools.cmake.cmakedeps:new)
self.cpp_info.type # The type of this artifact "shared-library", "static-library", etc (same as package_type)
self.cpp_info.location # full location (path and filename with extension) of the artifact
self.cpp_info.link_location # Location of the import library for Windows .lib associated to a dll
self.cpp_info.languages # same as "languages" attribute, it can be "C", "C++"
self.cpp_info.exe # Definition of an executable artifact
这些字段将从其他 cpp_info
和 components
定义中自动推导出来,例如 libs
或 libdirs
字段,但自动推导可能存在限制。显式定义它们将禁止自动推导,并使用 recipe 提供的的值。
此功能通过 -c tools.cmake.cmakedeps:new=will_break_next
配置启用。值 will_break_next
将在后续版本中更改,以强调此功能不适合在测试之外使用。只需启用此配置并强制构建使用 CMakeDeps
的包,就会触发新生成器的使用。
这个新的生成器也可以在 conanfile
文件中使用
[generators]
CMakeConfigDeps
class Pkg(ConanFile):
generators = "CMakeConfigDeps"
或
from conan import ConanFile
from conan.tools.cmake import CMakeConfigDeps
class TestConan(ConanFile):
def generate(self):
deps = CMakeConfigDeps(self)
deps.generate()
对于此 recipe CMakeConfigDeps
用法,仍然需要 -c tools.cmake.cmakedeps:new=will_break_next
,如果未启用配置,这些 recipe 将会失败。也可以定义 -c tools.cmake.cmakedeps:new=recipe_will_break
以专门启用 CMakeConfigDeps
生成器用法,而不是自动将现有的 CMakeDeps
替换为 CMakeConfigDeps
。
请注意,即使对于显式的 CMakeConfigDeps
生成器语法,该功能仍处于“孵化”阶段,此 recipe 可能会随时中断或删除。
如有任何反馈,请在 https://github.com/conan-io/conan/issues 中打开新工单。此反馈对于稳定功能并使其脱离孵化非常重要,因此即使它运行良好并且您没有发现任何问题,报告积极的反馈也非常有用。
工作区¶
可以通过定义环境变量 CONAN_WORKSPACE_ENABLE=will_break_next
来启用工作区功能。值 will_break_next
用于强调它将在后续版本中更改,并且此功能仅用于测试,不能在生产环境中使用。
启用该功能后,工作区由 conanws.yml
和/或 conanws.py
文件定义。默认情况下,任何 Conan 命令都会从当前工作目录向上遍历文件系统根目录,直到找到其中一个文件。这将定义“根”工作区文件夹。
conan workspace
命令允许打开工作区、向当前工作区添加和删除包。查看 conan workspace -h
帮助和子命令的帮助以查看其用法。
添加到工作区的依赖项作为本地 editable
依赖项工作。它们仅在当前工作区下解析为 editable
,如果当前目录移出工作区,则不再使用这些 editable
依赖项。
conanws
文件中的路径旨在相对于文件路径,以便在必要时可重新定位,或者可以提交到类似 monorepo 的项目中的 Git。
工作区文件语法¶
工作区最基本的实现是一个 conanws.yml
文件,其中仅包含属性的定义。例如,一个非常基本的工作区文件,仅定义当前的 CONAN_HOME 为本地文件夹,将是
home_folder: myhome
但是,conanws.yml
可以通过功能更强大的 conanws.py
进行扩展,后者遵循与 ConanFile
与其 conandata.yml
相同的关系,例如,它可以动态定义工作区 home,如下所示
from conan import Workspace
class MyWs(Workspace):
def home_folder(self):
# This reads the "conanws.yml" file, and returns "new_myhome"
# as the current CONAN_HOME for this workspace
return "new_" + self.conan_data["home_folder"]
因此,命令 conan config home
$ conan config home
/path/to/ws/new_myhome
将显示 new_myhome
文件夹作为当前的 CONAN_HOME(默认情况下,它相对于包含 conanws
文件的文件夹)
同样,定义 2 个 editables 的工作区 conanws.yml
可以是
editables:
dep1/0.1:
path: dep1
dep2/0.1:
path: dep2
但是,如果我们想动态定义 editables
,例如基于文件夹中是否存在某些 name.txt
和 version.txt
文件,则可以在 conanws.py
中将 editables 定义为
import os
from conan import Workspace
class MyWorkspace(Workspace):
def editables(self):
result = {}
for f in os.listdir(self.folder):
if os.path.isdir(os.path.join(self.folder, f)):
with open(os.path.join(self.folder, f, "name.txt")) as fname:
name = fname.read().strip()
with open(os.path.join(self.folder, f, "version.txt")) as fversion:
version = fversion.read().strip()
result[f"{name}/{version}"] = {"path": f}
return result
也可以在 set_name()
和 set_version()
方法中重用 conanfile.py
逻辑,使用 Workspace.load_conanfile()
助手
import os
from conan import Workspace
class MyWorkspace(Workspace):
def editables(self):
result = {}
for f in os.listdir(self.folder):
if os.path.isdir(os.path.join(self.folder, f)):
conanfile = self.load_conanfile(f)
result[f"{conanfile.name}/{conanfile.version}"] = {"path": f}
return result
工作区命令¶
conan workspace add/remove¶
使用这些命令向当前工作区添加或删除 editable 包。conan workspace add <path>
文件夹必须包含 conanfile.py
。
conanws.py
具有默认实现,但可以覆盖默认行为
import os
from conan import Workspace
class MyWorkspace(Workspace):
def name(self):
return "myws"
def add(self, ref, path, *args, **kwargs):
self.output.info(f"Adding {ref} at {path}")
super().add(ref, path, *args, **kwargs)
def remove(self, path, *args, **kwargs):
self.output.info(f"Removing {path}")
return super().remove(path, *args, **kwargs)
conan workspace info¶
使用此命令显示有关当前工作区的信息
$ cd myfolder
$ conan new workspace
$ conan workspace info
WARN: Workspace found
WARN: Workspace is a dev-only feature, exclusively for testing
name: myfolder
folder: /path/to/myfolder
products
app1
editables
liba/0.1
path: liba
libb/0.1
path: libb
app1/0.1
path: app1
conan workspace open¶
新的 conan workspace open
命令实现了一个新概念。那些在 conandata.yml
中包含 scm
信息(使用 git.coordinates_to_conandata()
)的包可以从其 Conan recipe 引用(包括 recipe 修订)自动克隆并检出到当前工作区中。
conan new workspace¶
conan new
命令学习了一个新的内置(实验性)模板 workspace
,它创建了一个包含一些 editable 包和一个表示它的 conanws.yml
的本地项目。它对于快速演示、概念验证和实验非常有用。
conan workspace build¶
conan workspace build
命令执行与 conan build <product-path> --build=editable
等效的操作,对于工作区中定义的每个 product
。
产品是“下游”消费者,是依赖关系图的“根”和起始节点。可以使用新的 --product
参数通过 conan workspace add <folder> --product
来定义它们。
conan workspace build
命令只是迭代所有产品,因此可能会重复构建产品的 editable 依赖项。在大多数情况下,这将是空操作,因为项目已经构建完成,但可能仍然需要一些时间。这有待优化,但这将在稍后完成,现在重要的是关注工具、UX、流程和定义(例如 products
的定义)。
conan workspace install¶
conan workspace install
命令可用于安装和构建当前工作区,作为 editable 的单体超级项目。请参阅下一节。
工作区单体构建¶
Conan 工作区可以构建为单个单体项目(有时称为超级项目),这可能非常方便。让我们通过一个示例来看看
$ conan new workspace
$ conan workspace install
$ cmake --preset conan-release # use conan-default in Win
$ cmake --build --preset conan-release
让我们解释一下发生了什么。首先,conan new workspace
创建了一个包含一些相关文件的模板项目
CMakeLists.txt
定义了超级项目,如下所示
cmake_minimum_required(VERSION 3.25)
project(monorepo CXX)
include(FetchContent)
function(add_project SUBFOLDER)
FetchContent_Declare(
${SUBFOLDER}
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/${SUBFOLDER}
SYSTEM
OVERRIDE_FIND_PACKAGE
)
FetchContent_MakeAvailable(${SUBFOLDER})
endfunction()
add_project(liba)
# They should be defined in the liba/CMakeLists.txt, but we can fix it here
add_library(liba::liba ALIAS liba)
add_project(libb)
add_library(libb::libb ALIAS libb)
add_project(app1)
因此,基本上,超级项目使用 FetchContent
添加子文件夹子项目。为了使其正常工作,子项目必须是基于 CMake 的子项目,并且带有 CMakeLists.txt
。此外,子项目必须定义正确的目标,就像 find_package()
脚本定义的目标一样,例如 liba::liba
。如果不是这种情况,始终可以定义一些本地 ALIAS
目标。
另一个重要的部分是 conanws.py
文件
from conan import Workspace
from conan import ConanFile
from conan.tools.cmake import CMakeDeps, CMakeToolchain, cmake_layout
class MyWs(ConanFile):
""" This is a special conanfile, used only for workspace definition of layout
and generators. It shouldn't have requirements, tool_requirements. It shouldn't have
build() or package() methods
"""
settings = "os", "compiler", "build_type", "arch"
def generate(self):
deps = CMakeDeps(self)
deps.generate()
tc = CMakeToolchain(self)
tc.generate()
def layout(self):
cmake_layout(self)
class Ws(Workspace):
def root_conanfile(self):
return MyWs # Note this is the class name
嵌入式 conanfile 的 class MyWs(ConanFile)
的角色很重要,它定义了超级项目所需的生成器和布局。
conan workspace install
不会单独安装不同的 editables,对于此命令,editables 不存在,它们只是被视为依赖关系图中的单个“节点”,因为它们将是超级项目构建的一部分。因此,只有一个生成的 conan_toolchain.cmake
和一组通用的依赖项 xxx-config.cmake
文件,用于所有超级项目的外部依赖项。
上面的模板在没有外部依赖项的情况下工作,但是当存在外部依赖项时,一切都将以相同的方式工作。这可以使用以下命令进行测试
$ conan new cmake_lib -d name=mymath
$ conan create .
$ conan new workspace -d requires=mymath/0.1
$ conan workspace install
$ cmake ...
注意
当前的 conan new workspace
生成一个基于 CMake 的超级项目。但是,可以使用其他构建系统定义超级项目,例如 MSBuild 解决方案文件,该文件添加了不同的 .vcxproj
子项目。只要超级项目知道如何聚合和管理子项目,这都是可能的。
如果存在某种结构,conanws.py
中的 add()
方法也可能管理将子项目添加到超级项目。
如有任何反馈,请在 https://github.com/conan-io/conan/issues 中打开新工单。