CMakeToolchain

CMakeToolchain 是 CMake 的工具链生成器。它生成一个工具链文件,该文件可以通过命令行调用 CMake 并使用 `-DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake` 来使用。此生成器将当前的包配置、设置和选项转换为 CMake 工具链语法。

它可以声明为

from conan import ConanFile

class Pkg(ConanFile):
    generators = "CMakeToolchain"

或者在 `generate()` 方法中完全实例化

from conan import ConanFile
from conan.tools.cmake import CMakeToolchain

class App(ConanFile):
    settings = "os", "arch", "compiler", "build_type"
    requires = "hello/0.1"
    generators = "CMakeDeps"
    options = {"shared": [True, False], "fPIC": [True, False]}
    default_options = {"shared": False, "fPIC": True}

    def generate(self):
        tc = CMakeToolchain(self)
        tc.variables["MYVAR"] = "MYVAR_VALUE"
        tc.preprocessor_definitions["MYDEFINE"] = "MYDEF_VALUE"
        tc.generate()

注意

CMakeToolchain 旨在与 `CMakeDeps` 依赖项生成器一起使用。请不要与它一起使用其他 CMake 遗留生成器(如 `cmake` 或 `cmake_paths`)。

生成的文件

在 `conan install`(或在缓存中构建包时)执行后,以及根据 `generate()` 方法中提供的信息以及从当前 `settings` 翻译的信息,将生成以下文件:

  • conan_toolchain.cmake:包含 Conan 设置到 CMake 变量的翻译。此文件中将定义的一些内容:

    • CMake 生成器平台和生成器工具集的定义

    • 基于 `fPIC` 选项定义的 `CMAKE_POSITION_INDEPENDENT_CODE`。

    • 必要时定义 C++ 标准

    • C++ 使用的标准库定义

    • 在 OSX 上禁用 rpaths

    • 在 Windows 上使用 Visual Studio 时定义 `CMAKE_VS_DEBUGGER_ENVIRONMENT`。这会设置 `PATH` 环境变量以指向包含 DLL 的目录,以便可以直接从 Visual Studio IDE 进行调试,而无需复制 DLL(需要 CMake 3.27)。

    • 定义 `CONAN_RUNTIME_LIB_DIRS` 以允许收集运行时依赖项(共享库),下方有详细说明。

  • conanvcvars.bat:在某些情况下,需要正确定义 Visual Studio 环境来进行构建,例如在使用 Ninja 或 NMake 生成器时。如果需要,`CMakeToolchain` 将生成此脚本,以便更容易定义正确的 Visual Studio 提示。

  • CMakePresets.json:此工具链会生成一个标准的 `CMakePresets.json` 文件。有关更多信息,请在此处参阅文档。它目前使用 JSON 模式的版本“3”。Conan 会向 JSON 文件添加 *configure*、*build* 和 *test* 预设条目。

    • 存储以下信息的 `configurePresets`:
      • 要使用的 `generator`。

      • 指向 `conan_toolchain.cmake` 的路径。

      • 与指定的设置对应的缓存变量,这些变量在工具链中指定时无法正常工作。

      • 单配置生成器的 `CMAKE_BUILD_TYPE` 变量。

      • 当配置 `tools.build:skip_test` 为 true 时,`BUILD_TESTING` 变量设置为 `OFF`。

      • 一个环境部分,设置与 VirtualBuildEnv 相关的所有环境信息(如果适用)。此环境可以在配方的 `generate()` 方法中通过 `CMakeToolchain.presets_build_environment` 属性传递环境来修改。可以通过使用 `tools.cmake.cmaketoolchain:presets_environment` 配置来跳过此部分的生成。

      • 默认情况下,预设名称将是 `conan-xxxx`,但可以使用 `CMakeToolchain.presets_prefix = “conan”` 属性自定义“conan-”前缀。

      • 预设名称由 `layout()` 的 `self.folders.build_folder_vars` 定义控制,其中可以包含设置、选项、`self.name` 和 `self.version` 以及常量 `const.xxx` 的列表,例如 `[“settings.compiler”, “settings.arch”, “options.shared”, “const.myname”]`。

      • 如果 CMake 作为直接的 `tool_requires` 依赖项找到,或者如果设置了 `tools.cmake:cmake_program`,则配置预设将包含一个 `cmakeExecutable` 字段。此字段表示用于此预设的 CMake 可执行文件的路径。如 CMake 文档所述,此字段保留供 IDE 使用,CMake 本身不使用它。

    • 存储以下信息的 `buildPresets`:
      • 与此构建预设相关联的 `configurePreset`。

    • 存储以下信息的 `testPresets`:
      • 与此构建预设相关联的 `configurePreset`。

      • 一个环境部分,设置与 VirtualRunEnv 相关的所有环境信息(如果适用)。此环境可以在配方的 `generate()` 方法中通过 `CMakeToolchain.presets_run_environment` 属性传递环境来修改。请注意,由于此预设继承自 `configurePreset`,因此它也将继承其环境。可以使用 `tools.cmake.cmaketoolchain:presets_environment` 配置来跳过此部分的生成。

  • CMakeUserPresets.json:如果在配方中声明了 `layout()` 并且 `CMakeLists.txt` 文件位于 `conanfile.source_folder` 文件夹中,则会生成 `CMakeUserPresets.json` 文件(如果尚不存在),其中会自动包含(在 `conanfile.generators_folder` 中的) `CMakePresets.json`,以便您的 IDE(Visual Studio、Visual Studio Code、CLion…)或 `cmake` 工具能够找到 `CMakePresets.json`。生成的 `CMakeUserPresets.json` 的位置可以通过 `user_presets_path` 属性进一步调整,如下文所述。生成的 `CMakeUserPresets.json` 的版本模式为“4”,需要 CMake >= 3.23。此文件的文件名可以使用 `CMakeToolchain.user_presets_path = "CMakeUserPresets.json"` 属性进行配置,因此如果您想生成“ConanPresets.json”并在您自己的文件中包含它,可以在 `generate()` 方法中定义 `tc.user_presets_path = "ConanPresets.json"`。有关完整示例,请参阅扩展您自己的 CMake 预设

    注意:如果 `CMakeUserPresets.json` 已存在且不是由 Conan 生成的,Conan 将跳过生成。

    注意:要列出所有可用的预设,请使用 `cmake --list-presets` 命令。

注意

生成的 `CMakeUserPresets.json` 的版本模式为 4(兼容 CMake >=3.23),而 `CMakePresets.json` 的模式为 3(兼容 CMake >=3.21)。

CONAN_RUNTIME_LIB_DIRS

在生成的 `conan_toolchain.cmake` 文件中,此变量包含主机上下文中所有依赖项的运行时库(如 DLL)所在目录的列表。这旨在用于依赖 CMake 功能来收集共享库以创建可重定位捆绑包,如以下示例所示。

只需将 `CONAN_RUNTIME_LIB_DIRS` 变量传递给 `install(RUNTIME_DEPENDENCY_SET ...)` 调用中的 `DIRECTORIES` 参数。

install(RUNTIME_DEPENDENCY_SET my_app_deps
    PRE_EXCLUDE_REGEXES
        [[api-ms-win-.*]]
        [[ext-ms-.*]]
        [[kernel32\.dll]]
        [[libc\.so\..*]] [[libgcc_s\.so\..*]] [[libm\.so\..*]] [[libstdc\+\+\.so\..*]]
    POST_EXCLUDE_REGEXES
        [[.*/system32/.*\.dll]]
        [[^/lib.*]]
        [[^/usr/lib.*]]
    DIRECTORIES ${CONAN_RUNTIME_LIB_DIRS}
)

自定义

preprocessor_definitions

此属性允许为多个配置(Debug、Release 等)定义编译器预处理器定义。

def generate(self):
    tc = CMakeToolchain(self)
    tc.preprocessor_definitions["MYDEF"] = "MyValue"
    tc.preprocessor_definitions.debug["MYCONFIGDEF"] = "MyDebugValue"
    tc.preprocessor_definitions.release["MYCONFIGDEF"] = "MyReleaseValue"
    # Setting to None will add the definition with no value
    tc.preprocessor_definitions["NOVALUE_DEF"] = None
    tc.generate()

这将转换为

  • 在 `conan_toolchain.cmake` 文件中为 `MYDEF` 定义一个 `add_compile_definitions()`。

  • 在 `conan_toolchain.cmake` 文件中使用 CMake 生成器表达式定义一个 `add_compile_definitions()`,用于不同配置的不同值。

cache_variables

此属性允许定义 CMake 缓存变量。这些变量与 `variables` 不同,是单配置的。它们将存储在 `CMakePresets.json` 文件中(在 `configurePreset` 的 `cacheVariables` 中),并在使用 `CMake()` 构建助手调用 `cmake.configure` 时使用 `-D` 参数进行应用。

def generate(self):
    tc = CMakeToolchain(self)
    tc.cache_variables["foo"] = True
    tc.cache_variables["foo2"] = False
    tc.cache_variables["var"] = "23"

分配给 `cache_variable` 的布尔值将被转换为 CMake 中的 `ON` 和 `OFF` 符号。

variables

此属性允许为多个配置(Debug、Release 等)定义 CMake 变量。这些变量应用于定义与工具链相关的内容,并且在大多数情况下,您可能需要使用 cache_variables。此外,请注意,由于这些变量定义在 `conan_toolchain.cmake` 文件内部,并且 CMake 会多次加载工具链,因此这些变量将在那些点上进行定义。

def generate(self):
    tc = CMakeToolchain(self)
    tc.variables["MYVAR"] = "MyValue"
    tc.variables.debug["MYCONFIGVAR"] = "MyDebugValue"
    tc.variables.release["MYCONFIGVAR"] = "MyReleaseValue"
    tc.generate()

这将转换为

  • 在 `conan_toolchain.cmake` 文件中为 `MYVAR` 定义一个 `set()`。

  • 在 `conan_toolchain.cmake` 文件中使用 CMake 生成器表达式定义一个 `set()`,用于不同配置的不同值。

分配给变量的布尔值将被转换为 CMake 中的 `ON` 和 `OFF` 符号。

def generate(self):
    tc = CMakeToolchain(self)
    tc.variables["FOO"] = True
    tc.variables["VAR"] = False
    tc.generate()

将生成句子:`set(FOO ON ...)` 和 `set(VAR OFF ...)`。

user_presets_path

此属性允许指定生成的 `CMakeUserPresets.json` 文件的位置。接受的值:

  • 绝对路径

  • 相对于 `self.source_folder` 的路径

  • 布尔值 `False`,完全禁止生成文件。

例如,我们可以通过以下方式阻止生成器创建 `CMakeUserPresets.json`:

def generate(self):
    tc = CMakeToolchain(self)
    tc.user_presets_path = False
    tc.generate()

还可以使用 `tools.cmake.cmaketoolchain:user_presets` 实验性配置来更改 `CMakeUserPresets.json` 文件名和位置。将其分配给空字符串将禁用文件生成。有关更多信息,请查看 conf 部分

presets_build_environment, presets_run_environment

这些属性分别通过分配 Environment 来修改与预设关联的构建和运行环境。这可以在 `generate()` 方法中完成。

例如,您可以覆盖构建环境中已设置的环境变量的值:

def generate(self):
    buildenv = VirtualBuildEnv(self)
    buildenv.environment().define("MY_BUILD_VAR", "MY_BUILDVAR_VALUE_OVERRIDDEN")
    buildenv.generate()

    tc = CMakeToolchain(self)
    tc.presets_build_environment = buildenv.environment()
    tc.generate()

或者生成一个新环境并将其与现有环境组合:

def generate(self):
    runenv = VirtualRunEnv(self)
    runenv.environment().define("MY_RUN_VAR", "MY_RUNVAR_SET_IN_GENERATE")
    runenv.generate()

    env = Environment()
    env.define("MY_ENV_VAR", "MY_ENV_VAR_VALUE")
    env = env.vars(self, scope="run")
    env.save_script("other_env")

    tc = CMakeToolchain(self)
    tc.presets_run_environment = runenv.environment().compose_env(env)
    tc.generate()

额外的编译标志

您可以使用以下属性将额外的编译标志追加到工具链:

  • extra_cxxflags(默认为 `[]`),用于额外的 cxxflags。

  • extra_cflags(默认为 `[]`),用于额外的 cflags。

  • extra_sharedlinkflags(默认为 `[]`),用于额外的共享链接标志。

  • extra_exelinkflags(默认为 `[]`),用于额外的可执行文件链接标志。

注意

标志优先级:在 `tools.build` 配置中指定的标志,例如 `cxxflags`、`cflags`、`sharedlinkflags` 和 `exelinkflags`,将始终优先于 CMakeToolchain 属性设置的标志。

presets_prefix

默认值为 `"conan"`,它将生成名为“conan-xxxx”的 CMake 预设。这样做是为了避免与用户自己的预设发生潜在的名称冲突。

absolute_paths

默认情况下,`CMakeToolchain` 将生成相对路径。例如,`CMakeUserPresets.json` 将包含指向包含的 `CMakePresets.json`(两者均由 `CMakeToolchain` 生成)的相对路径,而 `CMakePresets.json` 文件将在其 `toolchainFile` 字段中包含指向 `conan_toolchain.cmake` 的相对路径,该路径相对于构建文件夹,如 CMake 预设文档中所述。

如果出于某种原因需要使用绝对路径,可以通过以下方式实现:

def generate(self):
    tc = CMakeToolchain(self)
    tc.absolute_paths = True
    tc.generate()

使用自定义工具链文件

提供自定义 CMake 工具链文件有两种方式:

  • 可以完全跳过 `conan_toolchain.cmake` 文件,并用用户提供的文件替换它,方法是定义 `tools.cmake.cmaketoolchain:toolchain_file=<filepath>` 配置值。请注意,这种方法会将所有工具链的责任转移给用户提供的工具链,但像定位来自依赖项的必需的 `xxx-config.cmake` 文件等事情可能会很困难,而无需一些帮助。因此,在大多数情况下,推荐使用以下 `tools.cmake.cmaketoolchain:user_toolchain`,并在必要时使用 `tools.cmake.cmaketoolchain:enabled_blocks`。

  • 可以通过使用下方描述的 `user_toolchain` 块,并定义 `tools.cmake.cmaketoolchain:user_toolchain=["<filepath>"]` 配置值,将自定义用户工具链文件添加到 `conan_toolchain.cmake` 中(从中包含)。

    可以在 `global.conf` 中定义 `tools.cmake.cmaketoolchain:user_toolchain=["<filepath>"]` 配置,也可以通过创建 Conan 包来提供工具链,并使用 `self.conf_info` 来声明工具链文件。

    import os
    from conan import ConanFile
    class MyToolchainPackage(ConanFile):
        ...
        def package_info(self):
            f = os.path.join(self.package_folder, "mytoolchain.cmake")
            self.conf_info.define("tools.cmake.cmaketoolchain:user_toolchain", [f])
    

    如果将上述包声明为 `tool_requires`,工具链将自动应用。

  • 如果您有多个 `tool_requires` 定义,您可以在每个定义中使用 `append` 方法轻松地将所有用户工具链值组合起来,例如:

    import os
    from conan import ConanFile
    class MyToolRequire(ConanFile):
        ...
        def package_info(self):
            f = os.path.join(self.package_folder, "mytoolchain.cmake")
            # Appending the value to any existing one
            self.conf_info.append("tools.cmake.cmaketoolchain:user_toolchain", f)
    

    因此,它们将由您的 `CMakeToolchain` 生成器自动应用,而无需编写任何额外的代码。

    from conan import ConanFile
    from conan.tools.cmake import CMake
    class Pkg(ConanFile):
        settings = "os", "compiler", "arch", "build_type"
        exports_sources = "CMakeLists.txt"
        tool_requires = "toolchain1/0.1", "toolchain2/0.1"
        generators = "CMakeToolchain"
    
        def build(self):
            cmake = CMake(self)
            cmake.configure()
    

注意

重要提示

  • 在大多数情况下,`tools.cmake.cmaketoolchain:user_toolchain` 将优先于 `tools.cmake.cmaketoolchain:toolchain_file`。

  • `user_toolchain` 文件可以定义用于交叉编译的变量,例如 `CMAKE_SYSTEM_NAME`、`CMAKE_SYSTEM_VERSION` 和 `CMAKE_SYSTEM_PROCESSOR`。如果这些变量在用户工具链文件中定义,它们将被尊重,而 `conan_toolchain.cmake` 中推导出的变量将不会覆盖用户定义的变量。如果这些变量未在用户工具链文件中定义,则将使用 Conan 自动推导的变量。在 `user_toolchain` 文件中定义的这些变量也比配置中定义的变量(如 `tools.cmake.cmaketoolchain:system_name`)具有更高的优先级。

  • `tools.cmake.cmaketoolchain:enabled_blocks` 的使用可以与 `tools.cmake.cmaketoolchain:user_toolchain` 一起使用,只启用某些块,但避免 CMakeToolchain 覆盖用户工具链文件中定义的 CMake 值。

扩展和高级自定义

`CMakeToolchain` 实现了一种强大的功能,用于扩展和自定义生成的工具链文件。

内容按可自定义的 `blocks` 组织。以下预定义块可用,并按此顺序添加:

  • user_toolchain:允许从 `conan_toolchain.cmake` 文件包含用户工具链。如果定义了 `tools.cmake.cmaketoolchain:user_toolchain=["xxxx", "yyyy"]` 配置,则其值将作为 `conan_toolchain.cmake` 的第一行 `include(xxx)\ninclude(yyyy)`。

  • generic_system:定义 `CMAKE_SYSTEM_NAME`、`CMAKE_SYSTEM_VERSION`、`CMAKE_SYSTEM_PROCESSOR`、`CMAKE_GENERATOR_PLATFORM`、`CMAKE_GENERATOR_TOOLSET`。

  • compilers:根据 `tools.build:compiler_executables` 配置为不同语言定义 `CMAKE__COMPILER`。

  • android_system:定义 `ANDROID_PLATFORM`、`ANDROID_STL`、`ANDROID_ABI`,并包含 `ANDROID_NDK_PATH/build/cmake/android.toolchain.cmake`,其中 `ANDROID_NDK_PATH` 在 `tools.android:ndk_path` 配置值中定义。

  • apple_system:定义 Apple 系统上的 `CMAKE_OSX_ARCHITECTURES`(请参阅 通用二进制文件部分)、`CMAKE_OSX_SYSROOT`。

  • fpic:当存在 `options.fPIC` 时定义 `CMAKE_POSITION_INDEPENDENT_CODE`。

  • arch_flags:在必要时定义 C/C++ 标志,如 `-m32`、`-m64`。

  • linker_scripts:定义任何提供的链接器脚本的标志。

  • libcxx:在必要时定义 `-stdlib=libc++` 标志以及 `_GLIBCXX_USE_CXX11_ABI`。

  • vs_runtime:将 `CMAKE_MSVC_RUNTIME_LIBRARY` 变量定义为生成器表达式,用于多个配置。

  • vs_debugger_environment:仅限于 Visual Studio,从依赖项的“bindirs”文件夹定义 `CMAKE_VS_DEBUGGER_ENVIRONMENT`。

  • cppstd:定义 `CMAKE_CXX_STANDARD`、`CMAKE_CXX_EXTENSIONS`。

  • parallel:为 Visual Studio 定义 `/MP` 并行构建标志。

  • extra_flags:从 `tools.build:cxxflags`、`tools.build:cflags`、`tools.build:defines`、`tools.build:sharedlinkflags` 等添加额外的定义、编译和链接标志。

  • cmake_flags_init:根据先前定义的 Conan 变量定义 `CMAKE_XXX_FLAGS` 变量。上述块仅定义 `CONAN_XXX` 变量,此块将定义 CMake 变量,如 `set(CMAKE_CXX_FLAGS_INIT "${CONAN_CXX_FLAGS}" CACHE STRING "" FORCE)`。

  • extra_variables:从 `tools.cmake.cmaketoolchain:extra_variables` 定义额外的 CMake 变量。

  • try_compile:停止处理工具链,跳过此块以下的块,如果定义了 `IN_TRY_COMPILE` CMake 属性。

  • find_paths:定义 `CMAKE_FIND_PACKAGE_PREFER_CONFIG`、`CMAKE_MODULE_PATH`、`CMAKE_PREFIX_PATH`,以便找到 `CMakeDeps` 生成的文件。

  • pkg_config:根据 `tools.gnu:pkg_config` 定义 `PKG_CONFIG_EXECUTABLE`,并将 `CMAKE_CURRENT_LIST_DIR` 添加到 `ENV{PKG_CONFIG_PATH}`,以便 pkg-config 找到生成的 .pc 文件。

  • rpath:定义 `CMAKE_SKIP_RPATH`。默认情况下它是禁用的,如果您想激活 `CMAKE_SKIP_RPATH`,则需要定义 `self.blocks["rpath"].skip_rpath=True`。

  • shared:定义 `BUILD_SHARED_LIBS`。

  • output_dirs:定义 `CMAKE_INSTALL_XXX` 变量。

    • CMAKE_INSTALL_PREFIX:使用 `package_folder` 设置,因此如果运行“cmake install”操作,工件将转到该位置。

    • CMAKE_INSTALL_BINDIRCMAKE_INSTALL_SBINDIRCMAKE_INSTALL_LIBEXECDIR:默认设置为 `bin`。

    • CMAKE_INSTALL_LIBDIR:默认设置为 `lib`。

    • CMAKE_INSTALL_INCLUDEDIRCMAKE_INSTALL_OLDINCLUDEDIR:默认设置为 `include`。

    • CMAKE_INSTALL_DATAROOTDIR:默认设置为 `res`。

    如果您想更改默认值,请在 `layout()` 方法中调整 `cpp.package` 对象。

    def layout(self):
        ...
        # For CMAKE_INSTALL_BINDIR, CMAKE_INSTALL_SBINDIR and CMAKE_INSTALL_LIBEXECDIR, takes the first value:
        self.cpp.package.bindirs = ["mybin"]
        # For CMAKE_INSTALL_LIBDIR, takes the first value:
        self.cpp.package.libdirs = ["mylib"]
        # For CMAKE_INSTALL_INCLUDEDIR, CMAKE_INSTALL_OLDINCLUDEDIR, takes the first value:
        self.cpp.package.includedirs = ["myinclude"]
        # For CMAKE_INSTALL_DATAROOTDIR, takes the first value:
        self.cpp.package.resdirs = ["myres"]
    

    注意

    在 `package_info()` 方法中更改 `self.cpp_info` 是无效的,需要改为定义 `self.cpp.package`。

  • variables:从 `CMakeToolchain.variables` 属性定义 CMake 变量。

  • preprocessor:从 `CMakeToolchain.preprocessor_definitions` 属性定义预处理器指令。

自定义内容块

每个块都可以通过多种方式自定义(请记住在自定义后调用 `tc.generate()`)。

# tc.generate() should be called at the end of every one

# remove an existing block, the generated conan_toolchain.cmake
# will not contain code for that block at all
def generate(self):
    tc = CMakeToolchain(self)
    tc.blocks.remove("generic_system")

# remove several blocks
def generate(self):
    tc = CMakeToolchain(self)
    tc.blocks.remove("generic_system", "cmake_flags_init")

# LEGACY: keep one block, remove all the others
# If you want to generate conan_toolchain.cmake with only that
# block. Use "tc.blocks.enabled()" instead
def generate(self):
    tc = CMakeToolchain(self)
    # this still leaves blocks "variables" and "preprocessor"
    # use "tc.blocks.enabled()"" instead
    tc.blocks.select("generic_system")

# LEGACY: keep several blocks, remove the other blocks
# Use "tc.blocks.enabled()" instead
def generate(self):
    tc = CMakeToolchain(self)
    # this still leaves blocks "variables" and "preprocessor"
    # use "tc.blocks.enabled()" instead
    tc.blocks.select("generic_system", "cmake_flags_init")

# keep several blocks, remove the other blocks
# This can be done from configuration with
# tools.cmake.cmaketoolchain:enabled_blocs
def generate(self):
    tc = CMakeToolchain(self)
    # Discard all the other blocks except ``generic_system``
    tc.blocks.enabled("generic_system")

# iterate blocks
def generate(self):
    tc = CMakeToolchain(self)
    for block_name in tc.blocks.keys():
        # do something with block_name
    for block_name, block in tc.blocks.items():
        # do something with block_name and block

# modify the template of an existing block
def generate(self):
    tc = CMakeToolchain(self)
    tmp = tc.blocks["generic_system"].template
    new_tmp = tmp.replace(...)  # replace, fully replace, append...
    tc.blocks["generic_system"].template = new_tmp

# modify one or more variables of the context
def generate(self):
    tc = CMakeToolchain(conanfile)
    # block.values is the context dictionary
    toolset = tc.blocks["generic_system"].values["toolset"]
    tc.blocks["generic_system"].values["toolset"] = "other_toolset"

# modify the whole context values
def generate(self):
    tc = CMakeToolchain(conanfile)
    tc.blocks["generic_system"].values = {"toolset": "other_toolset"}

# modify the context method of an existing block
import types

def generate(self):
    tc = CMakeToolchain(self)
    generic_block = toolchain.blocks["generic_system"]

    def context(self):
        assert self  # Your own custom logic here
        return {"toolset": "other_toolset"}
    generic_block.context = types.MethodType(context, generic_block)

# completely replace existing block
from conan.tools.cmake import CMakeToolchain

def generate(self):
    tc = CMakeToolchain(self)
    # this could go to a python_requires
    class MyGenericBlock:
        template = "HelloWorld"

        def context(self):
            return {}

    tc.blocks["generic_system"] = MyGenericBlock

# add a completely new block
from conan.tools.cmake import CMakeToolchain
def generate(self):
    tc = CMakeToolchain(self)
    # this could go to a python_requires
    class MyBlock:
        template = "Hello {{myvar}}!!!"

        def context(self):
            return {"myvar": "World"}

    tc.blocks["mynewblock"] = MyBlock

可以使用配置文件中的配置来选择哪些块是活动的,使用 `tools.cmake.cmaketoolchain:enabled_blocks` 配置。这是一个列表,所以执行

[conf]
tools.cmake.cmaketoolchain:enabled_blocks=["generic_system"]

将只保留 `generic_system` 块,并丢弃所有其他块。例如,当用户提供自己的工具链文件,并且他们不需要 Conan `CMakeToolchain` 定义任何标志或 CMake 变量(除了找到依赖项所需的路径)时,可以使用此功能。在这种情况下,应该可以这样做:

[conf]
tools.cmake.cmaketoolchain:user_toolchain+=my_user_toolchain.cmake
tools.cmake.cmaketoolchain:enabled_blocks=["find_paths"]

有关这些块的更多信息,请查看源代码。

查找依赖项路径

生成的 `conan_toolchain.cmake` 在其 `find_paths` 块中包含 `CMAKE_PROGRAM_PATH`、`CMAKE_LIBRARY_PATH`、`CMAKE_INCLUDE_PATH` 等变量的信息,这些变量允许 CMake 运行 `find_program()`、`find_file()` 以及其他特殊的“finder”例程,以在没有显式包和目标定义(通过整体推荐的 `find_package()`)的情况下找到工件。

使用新的正在开发的 `CMakeConfigDeps`,`conan_toolchain.cmake` 块 `find_paths` 不再自己定义信息,而是加载由 `CMakeConfigDeps` 生成器生成的新文件 `conan_cmakedeps_paths.cmake`。这样,创建依赖项信息的责任就落到了 `CMakeConfigDeps` 生成器上,并且在新文件可以在无法传递工具链的某些场景中使用。

交叉编译

`generic_system` 块包含一些基本的交叉编译功能。在一般情况下,用户希望提供自己的用户工具链来定义所有细节,这可以通过 `tools.cmake.cmaketoolchain:user_toolchain` 配置来实现。如果定义了这个 conf 值,`generic_system` 块将包含提供的文件,但不会进一步定义任何用于交叉编译的 CMake 变量。

如果未定义 `user_toolchain` 并且 Conan 检测到它正在交叉编译(因为构建和主机配置文件包含不同的操作系统或架构),它将尝试定义以下变量:

  • `CMAKE_SYSTEM_NAME`:如果定义了 `tools.cmake.cmaketoolchain:system_name` 配置,否则它将尝试自动检测。此块将考虑交叉编译(Android 系统由其他块管理),并且不是 x86_64、sparc 和 ppc 系统上的 64 位到 32 位构建。

  • `CMAKE_SYSTEM_VERSION`:如果定义了 `tools.cmake.cmaketoolchain:system_version` conf,否则(主机)`os.version` 的子集(如果已定义)。在 Apple 系统上,此 `os.version` 将转换为相应的 Darwin 版本。

  • `CMAKE_SYSTEM_PROCESSOR`:如果定义了 `tools.cmake.cmaketoolchain:system_processor` conf,否则(主机)`arch` 设置(如果已定义)。

macOS 上通用二进制文件的支持

警告

此功能是实验性的,可能会发生重大更改。有关更多信息,请参阅 Conan 稳定性 部分。

从 Conan 2.2.0 开始,macOS 上使用 CMakeToolchain 构建通用二进制文件有初步支持。要在 Conan 中指定多个架构以用于通用二进制文件,请在定义设置中的架构时使用 `|` 分隔符。此方法允许传递架构列表。例如,运行:

conan create . --name=mylibrary --version=1.0 -s="arch=armv8|x86_64"

将为 `mylibrary` 创建一个包含 `armv8` 和 `x86_64` 架构的通用二进制文件,方法是在 `conan_toolchain.cmake` 文件中将 `CMAKE_OSX_ARCHITECTURES` 设置为 `arm64;x86_64`。

警告

重要的是要注意,此方法不适用于 CMake 或 Autotools(通过 `CMakeToolchain` 和 `AutotoolsToolchain`)以外的构建系统。

请注意,此功能主要有利于为发布目的构建最终的通用二进制文件。Conan 默认管理每个架构一个二进制文件的行为通常提供更可靠、更无忧的体验。用户应谨慎,不要过度依赖此功能来满足更广泛的用例。

参考

class CMakeToolchain(conanfile, generator=None)
generate()

此方法将把生成的文件保存到 conanfile.generators_folder。

conf

CMakeToolchain 受以下 `[conf]` 变量影响:

  • tools.cmake.cmaketoolchain:toolchain_file:用于替换 `conan_toolchain.cmake` 文件的用户工具链文件。

  • tools.cmake.cmaketoolchain:user_toolchain:要从 `conan_toolchain.cmake` 文件包含的用户工具链列表。

  • tools.android:ndk_path:`ANDROID_NDK_PATH` 的值。

  • tools.android:cmake_legacy_toolchain:`ANDROID_USE_LEGACY_TOOLCHAIN_FILE` 的布尔值。如果给定值,则仅在 `conan_toolchain.cmake` 中定义。这将被 `tools.android:ndk_path` 配置中指定的 Android NDK 中的 CMake 工具链考虑(对于 r23c 及更高版本)。如果通过 `tools.build:cflags` 或 `tools.build:cxxflags` 定义了编译器标志,则可能需要将此设置设置为 `False`,以防止 Android 的旧 CMake 工具链覆盖这些值。如果设置为 `False`,请确保您使用的是 CMake 3.21 或更高版本。

  • tools.cmake.cmaketoolchain:system_name:在大多数情况下不是必需的,仅用于强制定义 `CMAKE_SYSTEM_NAME`。

  • tools.cmake.cmaketoolchain:system_version:在大多数情况下不是必需的,仅用于强制定义 `CMAKE_SYSTEM_VERSION`。

  • tools.cmake.cmaketoolchain:system_processor:在大多数情况下不是必需的,仅用于强制定义 `CMAKE_SYSTEM_PROCESSOR`。

  • tools.cmake.cmaketoolchain:enabled_blocks:定义启用的块并丢弃其他块。

  • tools.cmake.cmaketoolchain:extra_variables:类似于字典的 Python 对象,指定 CMake 变量名和值。值可以是普通字符串、数字或类似于字典的 Python 对象,它必须指定 `value`(字符串/数字)、`cache`(布尔值)、`type`(CMake 缓存类型)以及可选的 `docstring`(字符串:默认为变量名)和 `force`(布尔值)键。它可能会覆盖 CMakeToolchain 定义的变量,用户需自行承担风险。例如:

[conf]
tools.cmake.cmaketoolchain:extra_variables={'MY_CMAKE_VAR': 'MyValue'}

结果是:

set(MY_CMAKE_VAR "MyValue")

这将在稍后注入,以便它可以覆盖默认的 Conan 变量。

其他高级用法:

tools.cmake.cmaketoolchain:extra_variables={'MyIntegerVariable': 42, 'CMAKE_GENERATOR_INSTANCE': '${ENV}/buildTools/'}
tools.cmake.cmaketoolchain:extra_variables*={'CACHED_VAR': {'value': '/var/run', 'cache': True, 'type': 'PATH', 'docstring': 'test cache var', 'force': True}}

结果是:

set(MyIntegerVariable 42)
set(CMAKE_GENERATOR_INSTANCE "${ENV}/buildTools/")
set(CACHED_VAR "/var/run" CACHE BOOL "test cache var" FORCE)

此块注入 `$ {ENV_VARIABLE}`,稍后将被展开。它还定义了一个类型为 `PATH` 的缓存变量。

提示

使用配置数据运算符 `*=` 来**更新**(而不是重新定义)已经在配置文件或全局配置中设置的 conf 变量。

  • tools.cmake.cmaketoolchain:toolset_arch:将在 `conan_toolchain.cmake` 文件的 `CMAKE_GENERATOR_TOOLSET` 变量中添加 `,host=xxx` 指定符。

  • tools.cmake.cmaketoolchain:toolset_cuda:(实验性)将在 `conan_toolchain.cmake` 文件的 `CMAKE_GENERATOR_TOOLSET` 变量中添加 `,cuda=xxx` 指定符。

  • tools.cmake.cmake_layout:build_folder_vars:设置、选项、`self.name` 和 `self.version` 以及常量 `const.uservalue`,这将产生不同的构建文件夹和不同的 CMake 预设名称。

  • tools.cmake.cmaketoolchain:presets_environment:设置为 `'disabled'`,以防止将环境部分添加到生成的 CMake 预设中。

  • tools.cmake.cmaketoolchain:user_presets:(实验性)允许为 `CMakeUserPresets.json` 文件设置自定义名称或子文件夹。空字符串将完全禁用文件生成。

  • tools.build:cxxflags:将追加到 `CMAKE_CXX_FLAGS_INIT` 的额外 C++ 标志列表。

  • tools.build:cflags:将追加到 `CMAKE_C_FLAGS_INIT` 的纯 C 标志列表。

  • tools.build:sharedlinkflags:将追加到 `CMAKE_SHARED_LINKER_FLAGS_INIT` 的额外链接器标志列表。

  • tools.build:exelinkflags:将追加到 `CMAKE_EXE_LINKER_FLAGS_INIT` 的额外链接器标志列表。

  • tools.build:defines:将由 `add_definitions()` 使用的预处理器定义列表。

  • tools.apple:sdk_path:`CMAKE_OSX_SYSROOT` 的值。在一般情况下,它不是必需的,并且将通过设置值传递给 CMake。

  • tools.apple:enable_bitcode:启用/禁用 Bitcode Apple Clang 标志的布尔值,例如 `CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE`。

  • tools.apple:enable_arc:启用/禁用 ARC Apple Clang 标志的布尔值,例如 `CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC`。

  • tools.apple:enable_visibility:启用/禁用 Visibility Apple Clang 标志的布尔值,例如 `CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN`。

  • tools.build:sysroot:定义 `CMAKE_SYSROOT` 的值。

  • tools.microsoft:winsdk_version:根据 CMake 策略 `CMP0149` 定义 `CMAKE_SYSTEM_VERSION` 或 `CMAKE_GENERATOR_PLATFORM`。

  • tools.build:compiler_executables:类似于字典的 Python 对象,指定编译器作为键,编译器可执行文件路径作为值。这些键将映射如下:

    • `c`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_C_COMPILER`。

    • `cpp`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_CXX_COMPILER`。

    • `RC`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_RC_COMPILER`。

    • `objc`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_OBJC_COMPILER`。

    • `objcpp`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_OBJCXX_COMPILER`。

    • `cuda`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_CUDA_COMPILER`。

    • `fortran`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_Fortran_COMPILER`。

    • `asm`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_ASM_COMPILER`。

    • `hip`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_HIP_COMPILER`。

    • `ispc`:将在 *conan_toolchain.cmake* 中设置 `CMAKE_ISPC_COMPILER`。