去年写过一篇博客《conan入门(十九):封装第三方开源库cpp_redis示例》,当时通过自己写conanfile.py,实现了对第三方库cpp_redis的conan封装。当时使用的conan 1.45.0
时过一年多,conan版本也经过了很多次升级,最新的版本是2.x,不过为了保持兼容现在我使用的版本是1.60.0
当时使用的是conans.CMake
来实现cmake编译,而conan.tools.cmake.CMake
还在实验阶段。现在conans.CMake
已经被官方放弃(在2.0中已经不存在),conan.tools.cmake.CMake
转正成了官方推荐的cmake编译实现类,在1.60.0中conans.CMake
还继续支持,但也不再维护。
所以如果你之前的conanfile.py中是用conans.CMake
实现的,那么现在要转向使用conan.tools.cmake.CMake
和conan.tools.cmake.CMakeToolchain
如下是一个基于conans.CMake
的简单的conanfile.py示例
from conans import ConanFile, CMake
class ExampleConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "hello/0.1"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
def build(self):
cmake = CMake(self)
cmake.definitions["MY_VAR"] = "HELLO"
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
如下是一个基于conan.tools.cmake.CMake
的简单的conanfile.py示例,效果与上面的示例等价
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeToolchain, CMakeDeps
class App(ConanFile):
settings = "os", "arch", "compiler", "build_type"
requires = "hello/0.1"
options = {"shared": [True, False], "fPIC": [True, False]}
default_options = {"shared": False, "fPIC": True}
def generate(self):
# 通过 CMake交叉工具链文件定义传递给CMakeLists.txt的变量
tc = CMakeToolchain(self)
tc.variables["MY_VAR"] = "HELLO"
tc.generate()
deps = CMakeDeps(self)
deps.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
与conans.CMake
相比conan.tools.cmake.CMake
没有definitions
成员,定义传递给CMakeLists.txt的变量改为使用CMakeToolchain.variables
成员。
所以如果你要从conans.CMake
迁移到conan.tools.cmake.CMake
,基本上只要修改这部分代码就可以了。
如果你不想修改conanfile.py,仍然可以在conan 1.x下使用。但肯定不能使用conan 2.x。
既使conan 1.x下仍然支持conans.CMake
,但仍然可能会存在问题。
我是发现我去年写的基于conans.CMake
的conanfile.py脚本,基于conan 1.60.0本机编译仍然可以正常执行,但交叉编译就不正常了。直接的原因是像CONAN_CMAKE_TOOLCHAIN_FILE
这样的CONAN_XXX环境变量不再有效。
mnn是阿里开源的一个轻量级的深度神经网络引擎,支持深度学习的推理与训练。因为项目中需要用到它,所以我需要对它进行conan封装,以支持我们基于conan管理的项目的引用。
mnn代码比较成熟,项目结构清晰,对于conan封装的主要工作量就是将CMakeLists.txt脚本的option开关在conanfile.py的options中定义为对应的conan option,其他部分与前面conan.tools.cmake.CMake
的没有什么不同,以下为python代码
conanfile.py – 基于 mnn的1.2.7版本实现,由于mnn不同的版本,CMakeLists.txt中定义的option会有所不同,所以,如果你需要实现其他mnn版本的conan封装,可以在此文件基础上对照对应版本的CMakeLists.txt的option定义对python代码进行增减
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain
from conan.tools.env import VirtualBuildEnv
class MnnConan(ConanFile):
name = "mnn"
version = "1.2.7"
# Optional metadata
url = "https://github.com/alibaba/MNN"
description = "a highly efficient and lightweight deep learning framework"
topics = ("deep learning","ai","mnn")
tool_requires = "cmake/[>=3.15.7]"
package_type = "library"
# Binary configuration
settings = "os", "compiler", "build_type", "arch"
options = {
"use_system_lib": [True, False],
"build_hard": [True, False],
"shared": [True, False],
"win_runtime_mt": [True, False],
"orbid_multi_thread": [True, False],
"openmp": [True, False],
"use_thread_pool": [True, False],
"build_train": [True, False],
"build_demo": [True, False],
"build_tools": [True, False],
"build_quantools": [True, False],
"evaluation": [True, False],
"build_converter": [True, False],
"support_tflite_quan": [True, False],
"debug_memory": [True, False],
"debug_tensor_size": [True, False],
"gpu_trace": [True, False],
"portable_build": [True, False],
"sep_build": [True, False],
"aapl_fmwk": [True, False],
"with_plugin": [True, False],
"build_mini": [True, False],
"use_sse": [True, False],
"build_codegen": [True, False],
"enable_coverage": [True, False],
"build_protobuffer": [True, False],
"build_opencv": [True, False],
"internal_features": [True, False],
"metal": [True, False],
"opencl": [True, False],
"opengl": [True, False],
"vulkan": [True, False],
"arm82": [True, False],
"onednn": [True, False],
"avx512": [True, False],
"cuda": [True, False],
"tensorrt": [True, False],
"coreml": [True, False],
"build_benchmark": [True, False],
"build_test": [True, False],
"build_for_android_command": [True, False],
"use_logcat": [True, False],
"use_cpp11": [True, False],
}
default_options = {
"use_system_lib": False,
"build_hard": False,
"shared": False,
"win_runtime_mt": False,
"orbid_multi_thread": False,
"openmp": False,
"use_thread_pool": True,
"build_train": False,
"build_demo": False,
"build_tools": True,
"build_quantools": False,
"evaluation": False,
"build_converter": False,
"support_tflite_quan": True,
"debug_memory": False,
"debug_tensor_size": False,
"gpu_trace": False,
"portable_build": False,
"sep_build": False,
"aapl_fmwk": False,
"with_plugin": False,
"build_mini": False,
"use_sse": True,
"build_codegen": False,
"enable_coverage": False,
"build_protobuffer": True,
"build_opencv": False,
"internal_features": False,
"metal": False,
"opencl": False,
"opengl": False,
"vulkan": False,
"arm82": False,
"onednn": False,
"avx512": False,
"cuda": False,
"tensorrt": False,
"coreml": False,
"build_benchmark": False,
"build_test": False,
"build_for_android_command": False,
"use_logcat": True,
"use_cpp11": True,
}
# Sources are located in the same place as this recipe, copy them to the recipe
exports_sources = "CMakeLists.txt", "*/*"
def generate(self):
tc = CMakeToolchain(self)
tc.variables["MNN_USE_SYSTEM_LIB"] = self.options.use_system_lib
tc.variables["MNN_BUILD_HARD"] = self.options.build_hard
tc.variables["MNN_BUILD_SHARED_LIBS"] = self.options.shared
tc.variables["MNN_WIN_RUNTIME_MT"] = self.options.win_runtime_mt
tc.variables["MNN_FORBID_MULTI_THREAD"] = self.options.orbid_multi_thread
tc.variables["MNN_OPENMP"] = self.options.openmp
tc.variables["MNN_USE_THREAD_POOL"] = self.options.use_thread_pool
tc.variables["MNN_BUILD_TRAIN"] = self.options.build_train
tc.variables["MNN_BUILD_DEMO"] = self.options.build_demo
tc.variables["MNN_BUILD_TOOLS"] = self.options.build_tools
tc.variables["MNN_BUILD_QUANTOOLS"] = self.options.build_quantools
tc.variables["MNN_EVALUATION"] = self.options.evaluation
tc.variables["MNN_BUILD_CONVERTER"] = self.options.build_converter
tc.variables["MNN_SUPPORT_TFLITE_QUAN"] = self.options.support_tflite_quan
tc.variables["MNN_DEBUG_MEMORY"] = self.options.debug_memory
tc.variables["MNN_DEBUG_TENSOR_SIZE"] = self.options.debug_tensor_size
tc.variables["MNN_GPU_TRACE"] = self.options.gpu_trace
tc.variables["MNN_PORTABLE_BUILD"] = self.options.portable_build
tc.variables["MNN_SEP_BUILD"] = self.options.sep_build
tc.variables["MNN_AAPL_FMWK"] = self.options.aapl_fmwk
tc.variables["MNN_WITH_PLUGIN"] = self.options.with_plugin
tc.variables["MNN_BUILD_MINI"] = self.options.build_mini
tc.variables["MNN_USE_SSE"] = self.options.use_sse
tc.variables["MNN_BUILD_CODEGEN"] = self.options.build_codegen
tc.variables["MNN_ENABLE_COVERAGE"] = self.options.enable_coverage
tc.variables["MNN_BUILD_PROTOBUFFER"] = self.options.build_protobuffer
tc.variables["MNN_BUILD_OPENCV"] = self.options.build_opencv
tc.variables["MNN_INTERNAL"] = self.options.internal_features
# backend options
tc.variables["MNN_METAL"] = self.options.metal
tc.variables["MNN_OPENCL"] = self.options.opencl
tc.variables["MNN_OPENGL"] = self.options.opengl
tc.variables["MNN_VULKAN"] = self.options.vulkan
tc.variables["MNN_ARM82"] = self.options.arm82
tc.variables["MNN_ONEDNN"] = self.options.onednn
tc.variables["MNN_AVX512"] = self.options.avx512
tc.variables["MNN_CUDA"] = self.options.cuda
tc.variables["MNN_TENSORRT"] = self.options.tensorrt
tc.variables["MNN_COREML"] = self.options.coreml
# target options
tc.variables["MNN_BUILD_BENCHMARK"] = self.options.build_benchmark
tc.variables["MNN_BUILD_TEST"] = self.options.build_test
tc.variables["MNN_BUILD_FOR_ANDROID_COMMAND"] = self.options.build_for_android_command
tc.variables["MNN_USE_LOGCAT"] = self.options.use_logcat
tc.variables["MNN_USE_CPP11"] = self.options.use_cpp11
tc.generate()
cd = CMakeDeps(self)
cd.generate()
env = VirtualBuildEnv(self)
env.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
def package_info(self):
self.cpp_info.libs = ["mnn"]
~/.conan/profiles/aarch64-linux-gnu
include(default)
{% set target_host = "aarch64-linux-gnu" %}
# 指定交叉编译器安装位置
{% set compiler_install_prefix = "/opt/gcc-arm-8.2-2018.08-x86_64-aarch64-linux-gnu" %}
# 指定交叉编译器bin位置
{% set compiler_prefix = compiler_install_prefix + "/bin/" %}
# 使用添加在PATH的编译器
[settings]
arch=armv8
build_type=Release
compiler=gcc
compiler.libcxx=libstdc++11
compiler.version=8
os=Linux
#[tool_requires]
[options]
opencv/*:with_ffmpeg=False
opencv/*:with_gtk=False
opencv/*:openexr=False
[conf]
tools.cmake.cmaketoolchain:system_processor=aarch64
tools.build:compiler_executables={"c":"{{ compiler_prefix + target_host + "-gcc" }}","cpp":"{{ compiler_prefix + target_host + "-g++" }}","asm":"{{ compiler_prefix + target_host + "-gcc" }}"}
tools.build:sysroot={{ compiler_install_prefix + "/aarch64-linux-gnu/libc" }}
#tools.build:sysroot=/
tools.system.package_manager:mode=install
tools.system.package_manager:sudo=True
[buildenv]
CHOST={{ target_host }}
AR={{ compiler_prefix + target_host + "-ar" }}
AS={{ compiler_prefix + target_host + "-gcc" }}
RANLIB={{ compiler_prefix + target_host + "-ranlib" }}
CC={{ compiler_prefix + target_host + "-gcc" }}
CXX={{ compiler_prefix + target_host + "-g++" }}
FC={{ compiler_prefix + target_host + "-gfortran" }}
LD={{ compiler_prefix + target_host + "-ld" }}
STRIP={{ compiler_prefix + target_host + "-strip" }}
上面的conanfile.py代码我保存在码云仓库:
https://gitee.com/l0km/mnn.git conan1.2.7
分支
git clone https://gitee.com/l0km/mnn.git -b conan1.2.7
本机编译示例
cd mnn
conan create .
交叉编译
cd mnn
conan create . -pr:h aarch64-linux-gnu.jinja -pr:b default
《conan入门(一):conan 及 JFrog Artifactory 安装》
《conan入门(二):conan 服务配置-密码管理及策略》
《conan入门(三):上传预编译的库(artifact)》
《conan入门(四):conan 引用第三方库示例》
《conan入门(五):conan 交叉编译引用第三方库示例》
《conan入门(六):conanfile.txt conanfile.py的区别》
《conan入门(七):将自己的项目生成conan包》
《conan入门(八):交叉编译自己的conan包项目》
《conan入门(九):NDK交叉编译自己的conan包项目塈profile的定义》
《conan入门(十):Windows下Android NDK交叉编译Boost》
《conan入门(十一):Linux下Android NDK交叉编译Boost》
《conan入门(十二):Windows NDK 编译 boost报错:CMake was unable to find a build program … MinGW Makefile》
《conan入门(十三):conan info 命令的基本用法》
《conan入门(十四):conan new 命令的新特性–模板功能(–template)》
《conan入门(十五):AttributeError: ‘CMake‘ object has no attribute ‘definitions‘》
《conan入门(十六):profile template功能实现不同平台下profile的统一》
《conan入门(十七):支持android NDK (armv7,armv8,x86,x86_64)交叉编译的统一profile jinja2模板》
《conan入门(十八):Cannot recognize the Windows subsystem, install MSYS2/cygwin or specify a build_require》
《conan入门(十九):封装第三方开源库cpp_redis示例》
《conan入门(二十):封装只包含头文件(header_only)的库示例》
《conan入门(二十一):解决MinGW编译Openssl的编译错误:crypto/dso/dso_win32.c》
《conan入门(二十二):编译 openssl要求python 3.7以上版本》
《conan入门(二十三):Windows下MinGW编译libcurl》
《conan入门(二十四):通过CONAN_DISABLE_CHECK_COMPILER禁用编译器检查》
《conan入门(二十五):imports将包安装到本地项目或其他指定位置》
《conan入门(二十七):因profile [env]字段废弃导致的boost/1.81.0 在aarch64-linux-gnu下交叉编译失败》
《conan入门(二十八):解决conan 1.60.0下 arch64-linux-gnu交叉编译openssl/3.1.2报错问题》
《conan入门(二十九):对第三方库mnn进行Conan封装塈conans.CMake和conan.tools.cmake.CMake的区别》
《conan入门(三十):对腾讯ncnn进行Conan封装》
《conan入门(三十一):在命令行(shell)中从profile中读取配置参数》
《conan 入门(三十二):package_info中配置禁用CMakeDeps生成使用项目自己生成的config.cmake》
《conan 入门(三十三):requirements()指定header的可见性(transitive_headers)》
《conan 入门(三十四):conan 2.x实现对只有Makefile的项目(erpcgen)的封装示例》