xmake从入门到精通5:Android平台编译详解

1,375 阅读2分钟

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版本。

原文:tboox.org/cn/2019/11/…