前言
android studio在2.2开始已经全面接入了cmake,用来编译jni代码。所以我们的跨平台编译同样需要与时俱进,使用cmake来完成工作。如果你不是很了解cmake,也不用担心,跟着本文探索下去,能够了解一些最基本的用法(PS:博主之前也是完全不会,摸着石头过河的,现在也还是不会……)。
另外ndk版本使用了最新的r16b(16.1.4479499),这给之后带来了一些些问题。在最新的ndk版本中,已经将编译工具从gcc迁移到了clang,默认会使用clang进行编译。
toolchain地址位于 ${ANDROID_SDK}/ndk-bundle/toolchains/llvm内。关于llvm和clang的关系可以参考这张图。(更详细的内容就需要自己查了,不是本文内容。)
ok既然使用到了clang,那么使用的c++标准库STL自然是libc++标准库。
我们在代码中使用的头文件,比如string.h,都会位于${ANDROID_SDK}/ndk-bundle/source文件夹内,不同的stl库会使用不同的文件路径。
还有一部分在sysroot文件夹中,比如jni.h这个文件。
还有一个非常重要的东西在platforms文件夹中,这个文件夹包含了不同的android版本,同时每个版本中都有不同的指令集文件夹。每一个文件夹模拟了一个真机运行环境。
另外在开始之前,建议自己阅读下面几篇文章:
当然也请打开cmake的官方文档以便查阅。
正文
boost的编译实际上并不算复杂,比如我们可以直接使用
这个github项目已经替你实现了,这里我使用了1.65.1的版本。主要问题还是集中在如何放到自己项目中。
我们知道cmake提供了一个方法叫做find_package,具体参数请参见官方文档。作用是使用cmake提供的脚本自动搜索并载入相关的库。比如我们需要载入boost的库:
FIND_PACKAGE(Boost COMPONENTS filesystem REQUIRED)
Boost是库的名字,我们只需要载入其中一个组件filesystem。REQUIRED表示必须载入,没找到就报错。
实际上当调用find_package之后,cmake就回去寻找一个cmake的脚本,比如boost就回去寻找FindBoost.cmake的脚本。在android studio的环境下,他会到/Users/yxwang/Library/Android/sdk/cmake/3.6.4111459/share/cmake-3.6/Modules 这个文件夹下寻找。
正常情况,我们可以使用
set(Boost_ADDITIONAL_VERSIONS "1.65" "1.65.1")
set(Boost_NO_SYSTEM_PATHS ON)
set(BOOST_ROOT ${PROJECT_SOURCE_DIR}/src/main/cpp/boost/${ANDROID_ABI})
set(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE(Boost COMPONENTS filesystem REQUIRED)
这几行代码来设置一些先决条件,然后findboost.cmake脚本就能正常运行,并且替我们设置好一些变量。(其中BOOST_ROOT 表示boost的地址)
但是我发现我这边运行会出现问题,最后导致find失败,于是read the fucking source code!!
最终发现,问题出在了其中一行find_path命令上,理论上能根据设置的路径能够最终找到需要的头文件地址,并且存放在变量Boost_INCLUDE_DIR中。
但是我mac上发现find_path失效了。一定是缺失了某个配置,导致寻找路径出现了错误。甚至连find_path(VAL NAMES a.jpg PATH /somepath) 这种的绝对寻找都找不到…… PS在非ndk环境中似乎运行成功。如果有知道的朋友请一定留言告诉我……毕竟我是个小白
那么怎么办呢?既然你找不到,那就我直接来告诉你,所以代码就变成了这样
set(Boost_ADDITIONAL_VERSIONS "1.65" "1.65.1")
set(Boost_NO_SYSTEM_PATHS ON)
set(BOOST_ROOT ${PROJECT_SOURCE_DIR}/src/main/cpp/boost/${ANDROID_ABI})
set(Boost_INCLUDE_DIR ${BOOST_ROOT}/include/boost-1_65_1 )
set(Boost_LIBRARY_DIR ${BOOST_ROOT}/lib )
set(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE(Boost COMPONENTS filesystem REQUIRED)
我手动设置了Boost_INCLUDE_DIR的位置和 Boost_LIBRARY_DIR的位置。 (请注意大小写,这个大小写多浪费了我半天时间……)
好的,然后就可以像引入其他静态或者动态那样使用了比如,引入头文件
include_directories(${Boost_INCLUDE_DIR})
比如引入Link库
target_link_libraries(TKAT PRIVATE ${Boost_LIBRARIES} )
实际上调用了find_package之后还给你定义很多components的变量规则都一样,比如BOOST_FILESYSTEM_LIBRARY就表示filesystem单个库。
问题
这里笔者遇到了一个非常严重的问题,armeabi-v7a指令集的库打包失败。这是一个很严重的问题,如果这个使用最广的指令集包打不出来,基本上就等于没有作用。
看了build-android.sh,发现其中有一部分
if [ "$TOOLSET" = "cla