Android-NDK/JNI

AndroidStudio3.0环境,NDK使用CMake编So

2018-01-26  本文已影响264人  我心若氺

谷歌从AndroidStudio2.2以上就添加了Cmake方式来编译So库,
这种方式比起原来命令行式的ndk-build方便了不少,
也不需要Android.mk,Application.mk和JNI文件夹了。

在下方的谷歌Android官方链接可以看到一个中文NDK的教程。
https://developer.android.com/studio/projects/add-native-code.html
而这个链接是谷歌Android官方英文Cmake指南
https://developer.android.com/ndk/guides/cmake.html
这俩都要认真上网才能看。

Using Android Studio 2.2 and higher, you can use the NDK and CMake to compile C and C++ code into a native library. Android Studio then packages your library into your APK using Gradle, the IDE's integrated build system.

先说一下具体环境,使用的是,Windows10 + AndroidStudio3.0

新建一个NDK工程

首先创建一个新项目,选中Include C++ support,因为是NDK项目嘛(见图1)
然后一路点Next,可以选Empty Activity,Layout文件也不需要,
因为是为了编So库嘛,不是为了做apk。(见图2,图3)
最后则要选定C++标准,(比如C++11),异常,RTTI,(见图4)
就完成了,非常简单。

图片1.png 图片2.png 图片3.png 图片4.png

CMake构建

图片5.png
工程完成后,先关注下新建好的工程的目录结构,(见图5)
最主要看两个文件,app目录内的build.gradle和CMakeList.txt
build.gradle是gradle构建的配置定义文件,这里就不展开讲了,只关注和CMake相关的。
externalNativeBuild {
    cmake {
        cppFlags "-std=c++11 -frtti -fexceptions"
    }
}

externalNativeBuild {
    cmake {
        path "CMakeLists.txt"
    }
}

cppFlags是刚才选择的C++11,rtti和异常
CMakeList.txt则是接下来重点讲的

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
set(libs "${CMAKE_SOURCE_DIR}/libs")
add_library( # Sets the name of the library.
             native-lib
             # Sets the library as a shared library.
             SHARED
             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib
              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

cmake_minimum_required(VERSION 3.4.1)用来设置在编译本地库时我们需要的最小的cmake版本,AndroidStudio自动生成,我们几乎不需要自己管。
以下是几个常用命令:
set,CMake设置变量,变量在下面就可以使用
add_library用来设置编译生成的本地库的名字为native-lib,SHARED表示编译生成的是动态链接库(这个概念前面已经提到过了),src/main/cpp/native-lib.cpp表示参与编译的文件的路径,这里面可以写多个文件的路径。
find_library 是用来添加一些我们在编译我们的本地库的时候需要依赖的一些库,由于cmake已经知道系统库的路径,所以我们这里只是指定使用log库,然后给log库起别名为log-lib便于我们后面引用,此处的log库是我们后面调试时需要用来打log日志的库,是NDK为我们提供的。
target_link_libraries 是为了关联我们自己的库和一些第三方库或者系统库,这里把我们把自己的库native-lib库和log库关联起来。
set_target_properties 命令的意思是设置目标的一些属性来改变它们构建的方式。

常见用法:
1)设置输出路径
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/src/main/libs/${ANDROID_ABI})
修改So的生成路径至main/libs,与main/cpp同级。

2)引用第三方库,通过set_target_properties,
设置IMPORTED_LOCATION,就是被引入So库所在路径。

 add_library(usb-1.0.9
             SHARED
             IMPORTED
 )
 set_target_properties(usb-1.0.9
                       PROPERTIES IMPORTED_LOCATION
                      "${libs}/${ANDROID_ABI}/libusb-1.0.9.so")

3)为子目录编译So库文件,
有的时候,我们并不想把所有代码文件打包成单一个So,那么可以为子目录写一个CMakeList.txt,
在这个子CMakeList.txt内,add_library,target_link_libraries,
然后在主CMakeList.txt里加一句add_subdirectory(src/main/cpp/子目录路径),
这样就会为子目录也生成一个So库文件,
我们在主CMakeList.txt里可以像引用第三方库一样引用这个子目录了。
更多:
对多个So编译,这两篇文章写的很好的。
分别是子目录多Module编译多个So库文件。我就不赘述了。
子目录方式:http://blog.csdn.net/b2259909/article/details/58591898
多Module方式:https://www.jianshu.com/p/4e3c0c20c244

4)编译Debug版和Release版
target_link_libraries可以附带debug,optimized的参数
用法如下:

target_link_libraries( # Specifies the target library.
                       native-lib
                       debug/optimized
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

target_link_libraries(< target> [item1 [item2 […]]] [[debug|optimized|general] < item>] …)
这个更多的具体的用法,可以看后面附的CMake命令链接。

5)CMake引入CpuFeatures库
在CMakeList.txt里加这两句,然后就可以在target_link_libraries调用cpufeatures了

include(AndroidNdkModules)
android_ndk_import_module_cpufeatures()

target_link_libraries( # Specifies the target library.
                       native-lib
                       cpufeatures
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

更进一步学习CMake
https://www.zybuluo.com/khan-lau/note/254724
这篇文章很好,翻译了https://cmake.org/cmake-tutorial/,和CMake的80个命令
CMake的全部命令,官网链接:
https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html
CMake的帮助文档,官网链接:
https://cmake.org/cmake/help/latest/index.html

最后,编译So库


点击Make Project,各个ABI的So,就生成在相应的目录内了。
上一篇下一篇

猜你喜欢

热点阅读