--- title: xmake从入门到精通5:Android平台编译详解 tags: [xmake, lua, android, jni] date: 2019-11-15 author: Ruki outline: deep --- xmake是一个基于Lua的轻量级现代化c/c++的项目构建工具,主要特点是:语法简单易上手,提供更加可读的项目维护,实现跨平台行为一致的构建体验。 本文主要详细讲解如何通过xmake编译可在android下运行的库和可执行程序。 * [项目源码](https://github.com/xmake-io/xmake) * [官方文档](https://xmake.io/zh/) ### 准备工作 首先,我们需要先准备好编译android native库必须的ndk工具链,如果还没有可以从官网下载解压即可:[Android NDK](https://developer.android.com/ndk/) 如果是为了获取更好的向下兼容性,可以选择r16版本,因为这个是最后一个支持armeabi的版本,如果没什么特别需求,可以直接下载最新版。 ### NDK集成和编译 #### 手动配置NDK 我们只需要将解压后ndk目录路径传递给xmake完成配置,可以直接编译了,例如: ```bash $ 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`全局配置命令来设置它,确保永久生效。 ```bash $ 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库的版本,例如: ```bash $ 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版本来解决: ```bash $ xmake f -p android --ndk=xxx --ndk_sdkver=16 ``` ### arch的编译切换 目前xmake提供 `armv7-a`, `arm64-v8a`, `armv5te`, `mips`, `mips64`, `i386`,`x86_64`这些架构的配置编译,如果没有指定arch,那么默认会使用armv7架构。 手动修改arch方式如下: ```bash $ xmake f -p android --ndk=xxx -a arm64-v8a ``` ### Android相关配置设置 如果项目中需要配置一些只有android平台才有的编译设置,比如添加特定宏开关,链接库等,可以在xmake.lua中,通过`is_plat("android")`来判断处理。 ```lua 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++库刚集成进去不久,问题比较多,使用过程中容易遇到各种编译问题。 ```bash $ xmake f -p android --ndk=xxxx --ndk_cxxstl=gnustl_shared --ndk_sdkver=16 ``` #### 编译生成的可执行程序在设备上运行不起来? 通常是api版本设置太高,导致的不兼容问题,可以尝试调低api版本。