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

  • Post author:
  • Post category:其他




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_ABI



ANDROID_NATIVE_API_LEVEL



ANDROID_PLATFORM

环境变量,

默认编译的目标平台 armv7,所以对于armv8,x86或x86_64平台不可以直接使用。所以如下需要创建一个自定义的工具链文件,预先设置

ANDROID_ABI



ANDROID_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将包安装到本地项目或其他指定位置》



版权声明:本文为10km原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。