*bingo支持conan2组件构建配方迁移指南*

<table>
    <tr>
        <td>所属SIG组:</td>
        <td>CICD</td>
    </tr>
    <tr>
        <td>落入版本:</td>
        <td>25.09</td>
    </tr>
    <tr>
        <td>设计人员:</td>
        <td>姚顺</td>
    </tr>
    <tr>
        <td>日期:</td>
        <td>2025.09.08</td>
    </tr>
</table>

**Copyright © 2025 openUBMC Community**

# 迁移指南
## 迁移背景
<!-- 描述该需求的来源或背景，比如：支撑XXX功能、XXX优化等；以及该需求对用户（含组件）带来什么具体价值，如果没有该需求，对用户（含组件）带来什么损失； -->
随着社区Conan版本演进，conan 1.x 已经不受官方支持。Conan 2.x 是一个重大的版本更新，它修复了 Conan 1.x 中的许多设计问题，带来了更高的稳定性、更好的性能和一致性。迁移过程需要一些努力，但最终会带来更清晰、更可维护的配置。

## 核心思想转变
<!-- 描述该需求交付的整体功能，主要实现XXX功能，解决XXX问题，明确方案如何实现 -->

Conan 1.x: 灵活但复杂，允许很多“魔法”和隐式行为，导致学习曲线陡峭和不可预测性。

Conan 2.x: 显式优于隐式。要求更明确的声明，减少了全局状态和隐式特性，使得行为更加可预测和可靠。

## 一、迁移前准备
<!-- 描述该需求的业务使用场景，内容包括：
1) 场景出发条件及对象：什么角色/工具/接口等在什么具体情况下使用该特性，使用对象技能如何？
2) 使用时间及频度
3) 描述该特性主要有哪些场景、子场景及关键任务操作 -->
了解官方文档：最重要的步骤！ 随时查阅官方迁移指南。

[Conan 2.0 官方文档](https://docs.conan.io/2/)

[1.X to 2.0 Migration Guide](https://docs.conan.io/1/conan_v2.html)


## 二、conan使用的变更点和迁移步骤

1. 配置系统 (Settings, Options, Conf)

    Conan 1.x: settings、options、env 在全局、配置文件和命令行中混合，优先级规则复杂。

    Conan 2.x: 引入了更清晰的 conf 配置系统来管理各种工具和行为。

    迁移行动：

    将很多之前通过 env 环境变量或 [env] 配置文件设置的配置（如编译器路径、构建工具行为）改为使用 conf。

    在 profiles 中，使用 [conf] 部分而不是 [env]。
    
    ```ini
    # Conan 1 profile (旧)
    [env]
    CC=/path/to/my/gcc
    CXX=/path/to/my/g++

    # Conan 2 profile (新)
    [conf]
    tools.build:compiler_executables={"c": "/path/to/my/gcc", "cpp": "/path/to/my/g++"}
    ```
    在 conanfile.py 中，可以使用 self.conf 或 self.conf_info 来获取和设置配置。

2. conanfile.py 的语法变更

    这是迁移工作的核心。
    
    a) 导入和基类
    
    Conan 1: from conans import ConanFile

    Conan 2: from conan import ConanFile

    ```python
    # Conan 2
    from conan import ConanFile
    from conan.tools.files import copy, load
    # 其他常用 tools...
    from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
    from conan.tools.build import cross_building
    from conan.tools.scm import Git
    ```

    b) 属性 exports 和 exports_sources
    
    语法不变，但行为更精确。

    c) config_options() 和 configure()
    
    Conan 1: 用于在配置期（根据settings）修改 options。

    Conan 2: config_options() 只在 settings 已知后调用一次，configure() 可能会被多次调用（例如在依赖图展开时）。需要将逻辑正确地分配到这两个方法中。

    d) 方法 package() 和 package_info()
    
    package_info()：这是最大的变化之一。

    Conan 1: 使用 self.cpp_info.libs, self.cpp_info.includedirs, self.cpp_info.libdirs 等，并且这些路径默认是相对于包根目录的绝对路径。

    Conan 2: 默认路径是相对路径。强烈建议使用 self.cpp_info.libs 和 self.cpp_info.includedirs 来只指定名称和相对路径，让 CMakeDeps 等生成器正确处理它们。

    移除了 self.cpp_info.builddirs，通常不再需要。

    引入了 set_property 和 get_property 来提供更精细的元数据控制。

    e) 工具链集成 (CMake, MSBuild, etc.)
    
    Conan 1: 主要通过 self._cmake 或 CMake helper 以及 virtualenv 生成器等方式，方式不统一。

    Conan 2: 引入了显式的 Toolchain 和 Deps 概念，这是推荐的最佳实践。

    CMakeToolchain: 生成 conan_toolchain.cmake 文件。

    CMakeDeps: 生成 FindXXX.cmake 或 XXX-config.cmake 文件。

    在 generate() 方法中生成它们。

    ```python
    # Conan 2 - 现代写法
    from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps

    class MyConan(ConanFile):
        settings = "os", "compiler", "build_type", "arch"
        generators = "CMakeToolchain", "CMakeDeps" # 可选：在配方中声明默认生成器

        def generate(self):
            # 更推荐在这里创建，可以添加自定义逻辑
            tc = CMakeToolchain(self)
            tc.variables["MY_CUSTOM_VAR"] = "1"
            tc.generate()
    
            deps = CMakeDeps(self)
            deps.generate()

        def build(self):
            cmake = CMake(self)
            cmake.configure()
            cmake.build()
    ```

## 三、conan迁移清单和示例
一个简单的 conanfile.py 迁移示例：

Conan 1.x (旧)
```python
from conans import ConanFile, CMake

class HelloConan(ConanFile):
    name = "hello"
    version = "1.0"
    settings = "os", "compiler", "build_type", "arch"
    generators = "cmake"
    exports_sources = "src/*"

    def build(self):
        cmake = CMake(self)
        cmake.configure(source_folder="src")
        cmake.definitions["ENABLE_TEST"] = "ON"
        cmake.build()

    def package(self):
        self.copy("*.h", dst="include", src="src")
        self.copy("*.so", dst="lib", keep_path=False)
        self.copy("*.a", dst="lib", keep_path=False)

    def package_info(self):
        self.cpp_info.libs = ["hello"]
```

Conan 2.x (新)
```python
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan.tools.files import copy

# openUBMC中通过此变量判断组件构建使用的conan版本
# 如未声明则默认使用conan 1.x
required_conan_version = ">=2.13.0"


class HelloConan(ConanFile):
    name = "hello"
    version = "1.0"
    settings = "os", "compiler", "build_type", "arch"
    exports_sources = "src/*"

    # 推荐的布局，帮助简化路径
    def layout(self):
        cmake_layout(self, src_folder="src")

    def generate(self):
        tc = CMakeToolchain(self)
        tc.variables["ENABLE_TEST"] = "ON"
        tc.generate()

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def package(self):
        copy(self, "*.h", self.source_folder, dst=os.path.join(self.package_folder, "include"))
        copy(self, "*.so", self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
        copy(self, "*.a", self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)

    def package_info(self):
        self.cpp_info.libs = ["hello"]  #单个库

        self.cpp_info.componets["libhello1"].libs = ["hello1"]  #多个库需要分别设置
        self.cpp_info.componets["libhello1"].libdirs = ["usr/lib64"]
        self.cpp_info.componets["libhello1"].includedirs = ["include/hello1"]
        self.cpp_info.componets["libhello1"].set_property("cmake_target_name", "libhello1::libhello1") #默认是hello::libhello1, 可以自定义

```
## 四、CMakeLists.txt迁移清单和示例
一个简单的 CMakeLists.txt 迁移示例：

Conan 1.x (旧)
```txt
cmake_minimum_required(VERSION 3.14)

project(bios)
find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_search_module(GMODULE REQUIRED gmodule-2.0)

set(TARGET_LIB ${PROJECT_NAME})
set(BUILD_DIR temp)

# 在conan 1.x中需要定义，在conan 2.x中废弃
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()

file(GLOB_RECURSE SOURCES "*.h" "*.c")	
add_library(${MTD_LIB} SHARED ${SOURCES})	

target_include_directories(${MTD_LIB}	
    PUBLIC ${LUACLIB_SRC_DIR}
    PUBLIC ${CONAN_INCLUDE_DIRS}
    PUBLIC ${GLIB_INCLUDE_DIRS})	
target_link_libraries(${MTD_LIB}	
    PUBLIC ${CONAN_LIBS_HUAWEI_SECURE_C}
    PUBLIC ${GLIB2_LIBRARIES}	
    PUBLIC ${GMODULE_LIBRARIES}	
    PUBLIC cutils	
    PUBLIC logging)
```

Conan 2.x (新)
```txt
cmake_minimum_required(VERSION 3.14)

project(bios)
# 使用现代化的CMake语法
find_package(libmc4lua REQUIRED) #对应的是生产者定义的package_info里面的信息

find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_search_module(GMODULE REQUIRED gmodule-2.0)

set(TARGET_LIB ${PROJECT_NAME})
set(BUILD_DIR temp)

file(GLOB_RECURSE SOURCES "*.h" "*.c")	
add_library(${MTD_LIB} SHARED ${SOURCES})	

target_include_directories(${MTD_LIB}
    PUBLIC ${GLIB_INCLUDE_DIRS})
# 使用现代化的CMake语法
target_link_libraries(${MTD_LIB}
    PUBLIC ${GLIB2_LIBRARIES}
    PUBLIC libmc4lua::libmc4lua
    PUBLIC skynet::skynet
    PUBLIC liblogger::liblogger)
```

## 四、bingo工具迁移说明

当前，bingo工具和各个组件的编译脚本都已经适配conan2，且bingo最新版本能够同时支持conan1和conan2版本组件的构建。`bingo`工具的命令无任何变化，开发者仅需执行`bingo up`将bingo工具更新到最新版本，然后，直接拉取组件代码仓的最新代码，执行构建命令即可编译出包。

## 五、总结
迁移到 Conan 2 需要一些学习和适配工作，但收益是巨大的：

更快的速度和更低的内存占用。

更清晰、更可预测的行为。

更现代化的、一致的 API。

更好的长期支持和社区发展。
