如何在自定义构建系统中使用Conan component功能?求相关实现示例
Conan Component 功能常见问题解答
问题1:指定self.cpp_info.components["crypto"].names["cmake_find_package"] = "Crypto"的作用
这行配置是为cmake_find_package生成器指定该组件的对外暴露名称。Conan的cpp_info的names字段是不同构建系统生成器的命名映射:你的组件内部id是crypto,但当用户使用cmake_find_package生成器集成时,需要用find_package(OpenSSL REQUIRED COMPONENTS Crypto)来引入该组件,而非内部的crypto名,方便和不同构建系统的官方命名约定对齐。
问题2:非CMake构建系统如何分配文件到各component
component是Conan包的逻辑划分,和你用来编译代码的构建系统无关,操作步骤如下:
- 不管你用Makefile、Meson、Autotools还是其他构建系统,只需要在
package()方法中将所有头文件、库文件、二进制文件按你规划的路径安装到包目录中 - 在
package_info()方法中,给每个component单独分配对应的路径属性即可,示例:
# 假设你编译完有两个库:libmath.a、libstr.a,头文件分别放在include/math和include/str self.cpp_info.components["math"].libs = ["libmath"] self.cpp_info.components["math"].includedirs = ["include/math"] self.cpp_info.components["str"].libs = ["libstr"] self.cpp_info.components["str"].includedirs = ["include/str"]
问题3:如何将component拷贝到本地缓存
component是同一个Conan包内的逻辑模块,没有独立的物理包结构,不需要单独拷贝:
- 你正常执行
conan create或者conan export-pkg将完整包存入本地缓存时,所有component的元数据(包含路径、依赖、编译选项等)会和包文件一起存入缓存 - 后续消费时可以直接调用同一个包下的任意component,不需要额外操作
问题4:如何单独消费某一个component
不同构建系统的调用方式大同小异,核心是只指定你需要的component即可,Conan会自动过滤其他组件的编译参数、库依赖:
- CMake场景:
find_package(包名 REQUIRED COMPONENTS 你需要的组件名),链接时直接用target_link_libraries(你的目标 包名::组件名) - 其他构建系统:Conan对应生成器会生成每个component的独立依赖配置项,直接引用对应component的配置项即可,不需要引入整个包的所有配置
完整Demo:单包双组件创建+单独消费示例
第一步:创建带两个component的Conan包
我们创建一个名为mybase的包,包含两个独立组件:math(数学计算库)、str(字符串处理库)
- 包目录结构:
mybase-pkg/ ├── conanfile.py ├── src/ │ ├── math/ │ │ ├── math.h │ │ └── math.c │ └── str/ │ ├── str.h │ └── str.c └── Makefile
- conanfile.py内容:
from conans import ConanFile, RunEnvironment, tools class MyBaseConan(ConanFile): name = "mybase" version = "1.0.0" settings = "os", "compiler", "build_type", "arch" def build(self): # 这里用Makefile编译,也可以替换为任意构建系统 env_build = RunEnvironment(self) with tools.environment_append(env_build.vars): self.run("make all") def package(self): # 安装头文件 self.copy("*.h", dst="include/math", src="src/math") self.copy("*.h", dst="include/str", src="src/str") # 安装库文件 self.copy("*.a", dst="lib", keep_path=False) self.copy("*.lib", dst="lib", keep_path=False) def package_info(self): # 定义math组件 self.cpp_info.components["math"].libs = ["math"] self.cpp_info.components["math"].includedirs = ["include/math"] # 定义str组件 self.cpp_info.components["str"].libs = ["str"] self.cpp_info.components["str"].includedirs = ["include/str"]
- 执行打包命令,将包存入本地缓存:
conan create . my/test
第二步:单独消费指定component
我们以CMake消费math组件为例:
- 消费者目录结构:
myapp/ ├── conanfile.txt ├── CMakeLists.txt └── main.c
- conanfile.txt内容:
[requires] mybase/1.0.0@my/test [generators] cmake_find_package
- CMakeLists.txt内容:
cmake_minimum_required(VERSION 3.15) project(myapp C) find_package(mybase REQUIRED COMPONENTS math) add_executable(myapp main.c) # 仅链接math组件,不会引入str组件的任何配置 target_link_libraries(myapp mybase::math)
- main.c内容只需要引入math.h调用对应接口即可,不需要关心str组件的任何内容。如果需要单独消费
str组件,只需要把CMakeLists.txt里的COMPONENTS参数改为str,链接时用mybase::str即可。
内容的提问来源于stack exchange,提问作者chenx319
相关产品推荐
相关产品推荐

