xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验。
本文主要详细讲解如何通过xmake编译可在android下运行的库和可执行程序。
准备工作
首先,我们需要先准备好编译android native库必须的ndk工具链,如果还没有可以从官网下载解压即可:Android NDK
如果是为了获取更好的向下兼容性,可以选择r16版本,因为这个是最后一个支持armeabi的版本,如果没什么特别需求,可以直接下载最新版。
NDK集成和编译
手动配置NDK
我们只需要将解压后ndk目录路径传递给xmake完成配置,可以直接编译了,例如:
$ xmake f -p android --ndk=~/downloads/android-ndk-r19c
$ xmake
其中,-p android
用于切换到android平台,因为如果不指定平台,默认会编译当前主机平台的target程序。
通常,如果没特殊需求,上面的配置就可以完成android native程序的编译,目前xmake内置支持:binary, static, shared这三种基础target类型文件的生成,分别对应可执行程序,.a静态库,.so动态库。
NDK路径的全局配置
xmake f/config
命令仅仅是针对当前项目的配置,如果经常跨平台编译和配置切换都要重新设置一遍ndk路径,那么还是稍显繁琐。
我们可以通过xmake g/global
全局配置命令来设置它,确保永久生效。
$ xmake g --ndk=~/xxx/android-ndk-r19c
我们也可以通过设置ANDROID_NDK_HOME
全局环境变量来确保永久生效,这跟上述命令配置的效果是差不多的。
NDK路径的自动探测
通常情况下即使没有配置ndk路径,xmake还是会尝试默认检测一些常用路径,比如在macos下会自动探测是否存在以下路径:
~/Library/Android/sdk/ndk-bundle
这是mac下装完android studio自动创建的sdk目录,以及ndk的常用放置路径。
或者尝试从ANDROID_NDK_HOME这种环境变量中探测,如果存在的话。
如果能探测到,也就没必要再额外手动配置了。
C++ STL库配置切换
首先,我们先来介绍下,ndk提供的三种stl库版本
- stlport:早期ndk内置的stl库,现在基本已废弃
- gnustl:ndk r16b之前主要使用的stl库,但是自从r16b之后,也已经被google去掉了
- llvm-c++:r16b之后较新的ndk内置的stl库
因此,我们在编译android库的时候,需要根据自己的需求,选用stl,以及选用合适的ndk版本,而xmake通常会尽可能默认使用llvm-c++库,如果发现当前ndk版本比较老,会尝试退化到gnustl上去。
用户也可以手动修改stl库的版本,例如:
$ xmake f -p android --ndk=xxxx --ndk_cxxstl=gnustl_shared
具体,关于ndk_cxxstl选项的配置值,可以敲help查看,xmake f --help
,主要就是:
llvmstl_static
llvmstl_shared
gnustl_static
gnustl_shared
stlport_static
stlport_shared
API版本设置
如果在编译过程中,报出一些libc库符号找不到,通常有可能是api版本没设置对,因为有些libc函数,只有在高版本api下才存在。
这个时候,我们可以通过尝试手动修改api版本来解决:
$ xmake f -p android --ndk=xxx --ndk_sdkver=16
arch的编译切换
目前xmake提供 armv7-a
, arm64-v8a
, armv5te
, mips
, mips64
, i386
,x86_64
这些架构的配置编译,如果没有指定arch,那么默认会使用armv7架构。
手动修改arch方式如下:
$ xmake f -p android --ndk=xxx -a arm64-v8a
Android相关配置设置
如果项目中需要配置一些只有android平台才有的编译设置,比如添加特定宏开关,链接库等,可以在xmake.lua中,通过is_plat("android")
来判断处理。
target("test")
set_kind("shared")
add_files("src/*.c")
if is_plat("android") then
add_defines("ANDROID")
add_syslinks("log")
end
FAQ
遇到一些libc/stl库头文件找不到怎么办?
可以尝试修改stl库版本,和api版本来解决,比如ndk r16b 推荐使用gnustl库,因为这个版本的llvmc++库刚集成进去不久,问题比较多,使用过程中容易遇到各种编译问题。
$ xmake f -p android --ndk=xxxx --ndk_cxxstl=gnustl_shared --ndk_sdkver=16
编译生成的可执行程序在设备上运行不起来?
通常是api版本设置太高,导致的不兼容问题,可以尝试调低api版本。