conan入门(十七):支持android NDK (armv7,armv8,x86,x86_64)交叉编译的统一profile jinja2模板

本文介绍如何使用Jinja2模板来统一管理针对Android NDK的交叉编译配置,包括armv7, armv8, x86和x86_64四种平台。通过模板文件`android_clang.jinja`,可以根据环境变量或传入参数自动设置目标平台和API级别,简化了不同平台的profile维护。同时,文章还提供了独立模板的解决方案,为每个平台创建单独的模板文件,方便直接调用。通过示例展示了模板的使用方法,并提到了自定义CMake工具链文件`conan_ndk_toolchain.cmake`的必要性。

conan:支持android NDK (armv7,armv8,x86,x86_64)交叉编译的统一profile jinja2模板

上一篇博客《conan入门(十六):profile template功能实现不同平台下profile的统一》以Android NDK交叉编译为例介绍了jinja模板在conan profile中的应用。如果针对不同的Android目标平台(armv7,armv8,x86,x86_64)都要维护一个profile也是挺麻烦的。本文在此基础上,更进一步改进将android NDK 对不同平台armv7,armv8,x86,x86_64交叉编译的profile基本于同一个模板统一实现

android_clang.jinja

如下是基于jinja2模板语言规范实现的profiel统一模板文件,

$HOME/.conan/profiles/android_clang.jinja

include(default)
####################################################################################
# 基于NDK19C的profile模板                                                          #
####################################################################################
{# 获取当前平台名并转为小写,linux,windows,darwin....                              #}
{% set osname = platform.system() | lower                                         %}
{% set archname = {"AMD64": "x86_64"}.get(platform.machine(), platform.machine()) %}
{# 编译器执行程序后缀                                                             #}
{% set exe_suffix = {"Windows": ".cmd"}.get(platform.system(),"")                 %}
####################################################################################
# 从环境变量ANDROID_ABI中读取目标CPU架构,设置target_host,api_level                #
# 优先使用上级传入的 android_abi 变量,未定义则使用环境变量ANDROID_ABI              #
# 否则使用默认值armeabi-v7a                                                        #
####################################################################################
{% if not android_abi                                                             %}
{%     set android_abi = os.getenv("ANDROID_ABI","armeabi-v7a")                   %}
{% endif                                                                          %}
{% set target_host,target_arch,default_api_level = {
                "armeabi-v7a":("armv7a-linux-androideabi","armv7",16),
                "arm64-v8a"  :("aarch64-linux-android","armv8",21),
                "x86"        :("i686-linux-android","x86",16),
                "x86_64"     :("x86_64-linux-android","x86_64",21)}
                .get(android_abi,("unknow_host","unknow_arch",-1))                %}
{# 优先使用上级传入的 api_level 变量,未定义则使用环境变量ANDROID_NATIVE_API_LEVEL
   否则使用默认值 default_api_level                                               #}
{% if not api_level                                                               %}
{%     set api_level = os.getenv("ANDROID_NATIVE_API_LEVEL",default_api_level)    %}
{% endif                                                                          %}
# 从环境变量ANDROID_NDK中读取Android NDK安装位置
android_ndk={{ os.getenv("ANDROID_NDK") }}
[settings]
arch={{ target_arch }}
build_type=Release
compiler=clang
compiler.libcxx=c++_static
compiler.version=8
os=Android
os.api_level={{ api_level }}
[options]
{% if platform.system() == "Windows" %}
boost:addr2line_location=$android_ndk\toolchains\llvm\prebuilt\windows-x86_64\bin\x86_64-linux-android-addr2line.exe
{% endif %}
boost:without_stacktrace=True
[env]
{% set bin_path = "$android_ndk/toolchains/llvm/prebuilt/"~osname~"-"~archname~"/bin" %}
{% if platform.system() == "Windows" %}
# windows下替换路径分割符
PATH=[{{ bin_path | replace("/","\\") }}]
{% else %}
PATH=[{{ bin_path }}]
{% endif %}
CHOST={{ target_host }}
CC={{ target_host }}{{ api_level }}-clang{{ exe_suffix }}
CXX={{ target_host }}{{ api_level }}-clang++{{ exe_suffix }}
#########################################################################################
# 对于 32 位 ARM,编译器会使用前缀 armv7a-linux-androideabi,                            #
# 但 binutils 工具会使用前缀 arm-linux-androideabi。对于其他架构,所有工具的前缀都相同  #
# see also https://developer.android.com/ndk/guides/other_build_systems                 #
#########################################################################################
{% set binutils_prefix = { "armv7a-linux-androideabi":"arm-linux-androideabi"}
                          .get(target_host,target_host) %}
AR={{ binutils_prefix }}-ar
AS={{ binutils_prefix }}-as
RANLIB={{ binutils_prefix }}-ranlib
LD={{ binutils_prefix }}-ld
STRIP={{ binutils_prefix }}-strip
# 定义环境变量ANDROID_ABI,ANDROID_NATIVE_API_LEVEL,用于 conan_ndk_toolchain.cmake
ANDROID_ABI={{ android_abi }}
ANDROID_NATIVE_API_LEVEL={{ api_level }}
#########################################################################################
# 指定./conan/cmake/conan_ndk_toolchain.cmake 为cmake 工具链文件                        #
# ANDROID NDK默认提供的android.toolchain.cmake,                                         #
# 如果不指定ANDROID_ABI和 ANDROID_NATIVE_API_LEVEL或ANDROID_PLATFORM,                   #
# 默认编译的目标平台 armv7,所以不可以直接使用。                                         #
#########################################################################################
{% set toolchain = os.path.join(profile_dir, "..","cmake","conan_ndk_toolchain.cmake") %}
{% if platform.system() == "Windows" %}
CONAN_CMAKE_TOOLCHAIN_FILE={{ toolchain | replace("/","\\") }}
{% else %}
CONAN_CMAKE_TOOLCHAIN_FILE={{ toolchain }}
{% endif %}
CONAN_CMAKE_GENERATOR="Unix Makefiles"
[conf]
tools.android:ndk_path=$android_ndk

android_clang.jinja通过读取环境变量ANDROID_ABI或上级模板文件传入的android_abi定义来确定目标平台,如果都没有定义则默认为armv7,对于Android API Level也是同样的处理,通过上级模板文件传入的api_level定义来确定目标平台,未定义则根据不同的平台有不同的默认值.

android.toolchain.cmake

ANDROID NDK默认提供的工具链文件$ANDROID_NDK/build/cmake/android.toolchain.cmake, 如果不指定ANDROID_ABIANDROID_NATIVE_API_LEVELANDROID_PLATFORM环境变量,
默认编译的目标平台 armv7,所以对于armv8,x86或x86_64平台不可以直接使用。所以如下需要创建一个自定义的工具链文件,预先设置ANDROID_ABIANDROID_NATIVE_API_LEVEL变量

$HOME/.conan/cmake/conan_ndk_toolchain.cmake

# 根据环境变量ANDROID_NATIVE_API_LEVEL,ANDROID_ABI定义ANDROID_NATIVE_API_LEVEL,ANDROID_ABI
set(ANDROID_NATIVE_API_LEVEL $ENV{ANDROID_NATIVE_API_LEVEL})
set(ANDROID_ABI $ENV{ANDROID_ABI})
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH)
include($ENV{ANDROID_NDK}/build/cmake/android.toolchain.cmake)

android_clang.jinja 使用示例

以boost为例,Windows下NDK交叉armv8平台执行如下命令:

$ set ANDROID_ABI=arm64-v8a 
$ conan install boost/1.78.0@ -pr:h android_clang.jinja  -pr:b default --build missing

独立模板

如果觉得每次编译要多设置一个环境变量还是有点麻烦,那可以如下为armv7,armv8,x86,x86_64分别定义一个简单的模板文件

android_clang_armv7.jinja

{% set android_abi = "armeabi-v7a" %}
{% include 'android_clang.jinja' %}

android_clang_armv8.jinja

{% set android_abi = "arm64-v8a" %}
{% include 'android_clang.jinja' %}

android_clang_x86.jinja

{% set android_abi = "x86" %}
{% include 'android_clang.jinja' %}

android_clang_x86_64.jinja

{% set android_abi = "x86_64" %}
{% include 'android_clang.jinja' %}

以如下结构保存到$HOME/.conan文件夹下:

.conan
├── cmake
│   └── conan_ndk_toolchain.cmake
└── profiles
    ├── android_clang.jinja
    ├── android_clang_armv7.jinja
    ├── android_clang_armv8.jinja
    ├── android_clang_x86.jinja
    ├── android_clang_x86_64.jinja
    └── default

那么不论是Linux还是Windows都可以如下执行交叉编译

$ conan install boost/1.78.0@ -pr:h android_clang_x86.jinja  -pr:b default --build missing

参考资料

《Profile templates》

《Using toolchain from Android NDK》

conan系列文章

《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入门(二十六):使用make编译makefile》
《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)的封装示例》
《conan 入门(三十五):在conanfile.py中获取C++编译器完整路径的方法》
《conan入门(三十六):在set_version方法中从pom.xml中读取版本号实现动态版本定义》
《conan 入门(三十七):conan 2.x通过定义环境变量(environment)执行make编译只有Makefile的项目(erpcgen)》
《conan 入门(三十八):conan二进制包的兼容性及自定义package_id的方式》
《conan入门(三十九):conan 2.x 引用第三方库示例》

内容概要:本文系统介绍了基于核主成分分析(KPCA)的故障检测方法,重点实现了T²和Q统计指数的可视化,并提供了完整的Matlab代码实现与仿真分析流程。该方法通过核函数映射将原始非线性过程数据转换至高维特征空间,进行主成分提取与降维处理,进而构建T²和Q两种统计量用于监控系统运行状态,有效识别工业过程中的早期故障与异常行为。文中详细阐述了KPCA的数学原理、故障检测机制、控制限计算方法,并结合实际案例展示其在复杂非线性系统中的应用效果与优越性,具有较强的工程实用性。; 适合人群:具备一定信号处理、机器学习理论基础及Matlab编程能力的研究生、科研人员和工程技术人员,特别适用于从事工业过程监控、故障诊断、智能制造等相关领域的研究人员。; 使用场景及目标:①应用于化工、电力、制造等行业中关键设备的在线故障监测与早期预警;②作为学术研究中非线性降维与异常检测算法的对比基准;③帮助开发者掌握KPCA模型构建、参数调优及T²-Q统计图可视化等核心技术环节。; 阅读建议:建议读者结合所提供的Matlab代码进行动手实践,深入理解KPCA算法的核心步骤,重点关注核函数选择、主成分数确定及统计量阈值设定等关键参数的影响,以提升故障检测的灵敏度与准确性。
项目定位:一个基于检索增强生成(RAG)技术的旅游领域智能知识问答平台,实现旅游文档的自动化导入与智能问答。 核心技术栈:Python + FastAPI(后端服务)、LangGraph(工作流引擎)、Milvus(向量数据库)、MongoDB(文档数据库)、MinI O(对象存储)、BGE-M3(嵌入模型)、BGE-reranker(重排序模型)、通义千问 Qwen(大语言模型)、MinerU(PDF解析)、SSE( 实时通信)。 功能一:文档导入。用户上传 PDF 或 Markdown 旅游文档,系统通过 MinerU 将 PDF 转为 Markdown,提取图片上传至 MinIO 并调 用 VLM 生成摘要,再按标题层级智能切分文档,利用 BGE-M3 生成稠密+稀疏双向量存入 Milvus,最后通过 LLM 自动提取景点、线 路、酒店、餐厅、城市等实体信息,一并向量化存储。 功能二:智能问答。用户输入问题后,系统首先通过 LLM 分析意图和实体,若信息不明确则返回候选选项供用户交互式澄清;确认 后并行执行三路检索——向量检索(语义匹配)、HyDE 检索(假设性文档增强召回)、Web搜索(MCP协议获取实时信息),经 RRF 倒 数排名融合算法合并,再经 BGE-reranker 语义重排序剔除噪音,最终由 LLM 基于检索结果生成精准答案,支持 SSE 流式逐字输出 。 架构特点:导入和查询两条流程均基于 LangGraph 有向图编排,节点可插拔、异常有兜底;所有敏感配置外置于 .env 文件,环境 解耦;支持一键启动两个 FastAPI 服务(端口 8000 导入、8001 问答),开箱即用。
内容概要:本文档介绍了名为“【硕士论文复现】可再生能源发电与电动汽车的协同调度策略研究”的Matlab代码实现资源,聚焦于可再生能源(如风能、太阳能)与电动汽车在电力系统中的协同优化调度问题。研究通过构建多时间尺度的数学模型,结合智能优化算法(如粒子群、遗传算法、ADMM等),对电力系统调度、电动汽车充放电行为、储能配置及电网稳定性等问题进行仿真分析,旨在提升能源利用效率、降低碳排放并实现电网经济稳定运行。文档还列举了多个相关研究方向及配套代码资源,涵盖微电网优化、电氢耦合系统、需求响应、分布式调度等前沿领域,具有较强的学术与工程应用价值。; 适合人群:具备一定电力系统基础知识和Matlab编程能力,从事新能源、智能电网、电动汽车等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①复现硕士论文中的协同调度模型,掌握可再生能源与电动汽车联合优化的方法;②学习如何运用Matlab/Simulink进行电力系统建模与仿真;③为撰写学术论文、开展课题研究或工程项目提供技术支持与参考案例。; 阅读建议:建议结合文中提到的其他相关资源(如YALMIP工具包、优化算法代码等)共同使用,重点关注模型构建思路与算法实现细节,并通过实际运行代码加深理解。同时可关注公众号“荔枝科研社”获取完整资料与更新内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值