Workspace 文件

警告

此功能是新的孵化功能的一部分。这意味着它仍在开发中,并正在寻找用户测试和反馈。有关更多信息,请参阅 孵化部分

Workspace 由 conanws.yml 和/或 conanws.py 文件定义,这些文件将定义“根”workspace 文件夹。

conanws.yml

Workspace 最基本的实现是 conanws.yml 文件。它定义了 workspace 的 packages(可编辑的包)。例如,定义 2 个 packages 的 workspace conanws.yml 可能是

conanws.yml
packages:
   - path: dep1
     ref: dep1/0.1
   - path: dep2
     ref: dep2/0.1

此外,它可能没有 ref 字段,让 Conan 从各自的 path/conanfile.py 中读取 *name/version*。

conanws.yml
packages:
   - path: dep1
   - path: dep2

conanws.py

一个 conanws.yml 可以通过一个功能更强大的 conanws.py 扩展,它遵循与 ConanFile 及其 conandata.yml 之间的相同关系。如果我们要动态定义 packages,例如基于某些 name.txtversion.txt 文件是否存在,则可以在 conanws.py 中定义这些包,如下所示

conanws.py
import os
from conan import Workspace

class MyWorkspace(Workspace):

   def packages(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.append({"path": f, "ref": f"{name}/{version}"})
      return result

也可以在 set_name()set_version() 方法中使用 conanfile.py 逻辑,使用 Workspace.load_conanfile() 助手

conanws.py
import os
from conan import Workspace

class MyWorkspace(Workspace):
   def packages(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.append({"path": f, "ref": f"{conanfile.name}/{conanfile.version}"})
      return result

conanws.py super-build ConanFile

当计算 workspace 依赖关系图时,workspace 中的所有包都将折叠到依赖关系图中的单个节点,并且该节点将具有依赖关系到 Conan 缓存中安装的 workspace 外部的其他包。 conanws.py 文件可以包含代表 super-build 的 ConanFile 的定义。

定义 workspace super-build 项目的 ConanFile 如下所示

conanws.py
from conan import ConanFile, Workspace
from conan.tools.cmake import cmake_layout

class MyWs(ConanFile):
   settings = "os", "compiler", "arch", "build_type"
   generators = "CMakeToolchain", "CMakeDeps"

   def layout(self):
      cmake_layout(self)


class Ws(Workspace):
   def root_conanfile(self):
      return MyWs

它定义了我们的 super-build 项目将是一个 CMake 项目,该项目使用 CMakeToolchainCMakeDeps 生成器来集成和查找外部包依赖项。 ConanFile 根本不需要定义 requires,它们将通过聚合 workspace 中所有包的 requires 来计算。

重要

conanws.py 内部的 ConanFile 是一个特殊的 conanfile,仅用于 workspace super-build 定义布局和生成器。它不应该有任何类型的 requirements,既没有常规的 requirestool_requirestest_requires。它通过收集和聚合 workspace 包的 requirements 来获得其依赖项。它也不应该有 build()package() 方法。

conanws.py super-build workspace packages

使用 workspace_packages 属性,conanws.py super-build ConanFile 可以访问 workspace 包,以便能够重用它们的功能。例如,如果我们想要收集 workspace 包 toolchain 定义的行为,我们可以这样做。假设我们有一个包含 2 个包 pkga/1.2.3pkgb/2.3.4 的 workspace

pkga/conanfile.py
from conan import ConanFile

class PkgA(ConanFile):
   name = "pkga"
   version = "1.2.3"

   def configure_toolchain(self, tc):
      tc.preprocessor_definitions["PKGA_SOME_DEFINITION"] = self.version

   def generate(self):
      tc = CMakeToolchain(self)
      self.configure_toolchain(tc)
      tc.generate()
pkgb/conanfile.py
from conan import ConanFile
class PkgB(ConanFile):
   name = "pkgb"
   version = "2.3.4"

   def configure_toolchain(self, tc):
      tc.preprocessor_definitions["SOME_PKGB_DEFINE"] = self.version

   def generate(self):
      tc = CMakeToolchain(self)
      self.configure_toolchain(tc)
      tc.generate()
conanws.py
from conan import ConanFile
from conan import Workspace
from conan.tools.cmake import CMakeToolchain

class MyWs(ConanFile):
   settings = "arch", "build_type"
   def generate(self):
      tc = CMakeToolchain(self)
      for ref, dep in self.workspace_packages.items():
         dep.configure_toolchain(tc)
      tc.generate()

class Ws(Workspace):
   def root_conanfile(self):
      return MyWs

然后,workspace_packages.items() 迭代将能够调用 workspace 中的每个包 configure_toolchain() 并将它们的所有行为收集到当前的 super-build CMakeToolchain 中。生成的 toolchain 将包含 SOME_PKGB_DEFINE=2.3.4PKGA_SOME_DEFINITION=1.2.3 的定义。

警告

重要

访问 workspace_packages 到 workspace 包 ConanFiles 必须是**只读**和**纯粹**的。它不能修改 workspace pkgapkgb 包的数据,并且不能有任何副作用。例如,禁止调用任何方法,如 .build() 甚至 .generate() 方法。如果需要重用的逻辑,开发人员有责任定义一些约定,例如 configure_toolchain() 方法,如果从 conanws.py 调用,将完全不会修改(纯粹)pkgapkgb 数据。

conanws.py super-build options

上述 workspace_packages 访问的一个特殊情况是读取各个 workspace 包的选项。用于 super-build workspace 文件的 conanws.py 可以以两种不同的方式管理选项

  • 它可以定义自己的 options,使用正常的 conanfile.py 语法,以便生成的 conan_toolchain.cmake 使用这些输入。

  • 它可以收集 workspace 的选项,使用 workspace_packages 并以任何用户自定义的方式处理它们。

super-project options

一个 conanws.py 必须在 ConanFile 类中定义 super-build 的选项,并在 generate() 方法中使用这些选项,就像通常在 conanfile.py 文件中发生的那样,如下所示

from conan import ConanFile, Workspace

class MyWs(ConanFile):
   settings = "arch", "build_type"
   options = {"myoption": [1, 2, 3]}

   def generate(self):
      self.output.info(f"Generating with my option {self.options.myoption}!!!!")

class Ws(Workspace):
   def root_conanfile(self):
      return MyWs

然后,可以通过配置文件或命令行使用常规语法提供选项

$ conan workspace super-install -of=build -o "*:myoption=1"
> conanws.py base project Conanfile: Generating with my option 1!!!!

请注意,workspace 包中定义的 options 可能会重叠,因为对于 super-project 而言,这些选项会被简单地忽略,并且只有 super-project 的选项才会被考虑在内,以生成 conan_toolchain.cmake。例如,conanws.py 可以定义一个 shared 选项,如果希望 conan_toolchain.cmake 在定义类似 -o "*:shared=True" 时正确定义 BUILD_SHARED_LIBS,因为 workspace 包具有 shared 选项信息在 workspace 包折叠到依赖关系图中以模拟 super-project 时会被丢弃。

packages options

第二种替代方案是收集已折叠的 workspace 包的 options。回想一下,在最终的依赖关系图中,workspace 包不再被表示,因为它们不再是单独的包,而是作为当前 super-build 的一部分。访问其选项信息的方式是通过 workspace_packages,并且可以使用该信息在 generate() 方法中执行 super-build 项目级别的任何所需操作。

因此,假设一个包含 dep/0.1 包的 workspace,该包包含标准的 shared 选项,定义了以下 super-build ConanFile

from conan import ConanFile, Workspace

class MyWs(ConanFile):
   def generate(self):
      for pkg, dep in self.workspace_packages.items():
         for k, v in dep.options.items():
            self.output.info(f"Generating with opt {pkg}:{k}={v}!!!!")

class Ws(Workspace):
   def root_conanfile(self):
      return MyWs

然后,当定义 workspace 包选项时,workspace ConanFile 可以收集它们。

$ conan workspace super-install -of=build -o "*:shared=True"
> conanws.py base project Conanfile: Generating with opt dep/0.1:shared=True!!!!!!!!

注意

实际上,workspace 创建者有责任定义如何处理这些选项,无论是通过定义自己的选项还是收集 workspace 包的选项。请注意,不可能自动将 workspace 包选项映射到 super-project,因为选项是按包定义的。两个不同的包可能具有不同的 shared=Trueshared=False 值。此外,通常,对生成的 toolchain 文件的影响是自定义的,并在每个包的 generate() 方法中实现。这种影响是程序化的(不是声明性的),将所有这些影响聚合到一个 toolchain 中将非常具有挑战性。

另请参阅

阅读 Workspace 教程 部分。