上两篇文章中,只是讲了APP如何创建,他们都使用到了同一个CMakeList.txt文件,但是没有仔细分析这个文件的作用,现在就仔细分析一下.
首先什么是CMakeList.txt,它是一个构建工具CMake所使用的文件,CMake与Make工具类似,Make工具使用Makefile来确定编译规则,而CMake通过CMakeList来确定编译规则,这个CMakeList.txt就是CMake的构建脚本,Android Studio中默认使用CMake来构建C语言相关的文件。
在创建支持C++的工程时,如果勾选了 Include C++ Support复选框的话,Android Studio会为我们自动创建一个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.
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} )
我们来一步一步分解讲解它
1. 首先:
# 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)
来确定所需CMake的最小版本号。
2. 添加库
# 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.
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 )
通过add_library()来向CMake构建脚本中添加源文件或者库。add_library()的三个参数分别是:库名称,库属性(STATIC or SHARED),库路径。Android Studio在同步项目后会显示关联的头文件,不过,为了确保CMake在编译时能够找到头文件,还需要通过include_directories()命令添加到CMake构建脚本中,并指定头文件的路径。
add_library(...)
# Specifies a path to native header files.
include_directories(src/main/cpp/include/)
同时,CMake中使用的标准库文件的命名是:
lib库名称.so
例如,在构建脚本中指定"native-lib"作为共享库的名称,CMake将创建一个名称为 libnative-lib.so的文件。不过,在Java代码中加载此库时,将使用在CMake构建脚本中指定的名称。
static {
System.loadLibrary(“native-lib”);
}
同时也可以使用多个add_library()命令来添加多个库。比如在ffmpeg分开编译成多个库的情况下,就可以使用多个add_library()命令把他们都添加进去,如下所示:
add_library(native-lib
SHARED
src/main/cpp/native-lib.cpp )
set(JNI_LIBS_DIR ${CMAKE_SOURCE_DIR}/src/main/jniLibs)
add_library(avutil
SHARED
IMPORTED )
set_target_properties(avutil
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavutil.so )
add_library(swresample
SHARED
IMPORTED )
set_target_properties(swresample
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libswresample.so )
add_library(swscale
SHARED
IMPORTED )
set_target_properties(swscale
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libswscale.so )
add_library(avcodec
SHARED
IMPORTED )
set_target_properties(avcodec
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavcodec.so )
add_library(avformat
SHARED
IMPORTED )
set_target_properties(avformat
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavformat.so )
add_library(avfilter
SHARED
IMPORTED )
set_target_properties(avfilter
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavfilter.so )
add_library(avdevice
SHARED
IMPORTED )
set_target_properties(avdevice
PROPERTIES IMPORTED_LOCATION
${JNI_LIBS_DIR}/${ANDROID_ABI}/libavdevice.so )
include_directories(${JNI_LIBS_DIR}/includes)
同时,也许你已经注意到了,在每一个add_library()后面,都有一个set_target_properties(),这是因为,ffmpeg的库为不同的CPU架构提供了不同的软件包,并将其组织到单独的目录中了,所以要向CMake的构建脚本中添加库的多个ABI版本,而不必为每个版本的库编写多个命令,可以使用 ANDROID_ABI路径变量,此变量可以使用NDK支持的一组默认ABI,从而让Gradle自动选择对应的ABI,那么这个NDK默认支持的ABI是在哪指定的呢?就是在app/src/build.gradle中,咱们添加的
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
3. 使用原生的NDK API和库:
# 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 )
通过find_library()函数可以从NDK中找到NDK中支持的日志库,并将其路径保存为一个变量,如上面所示,${log-lib}就是该函数返回的路径变量,这个变量可以在其他地方被使用,比如下面要讲的关联库。
4. 关联库:
# 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} )
为了确保原生库可以在log库中调用函数,需要使用target_link_libraries()命令来关联库,比如在之前的例子中,如下所示:
target_link_libraries(native-lib
android
ffmpeg
${log-lib})
至此,这个CMakeList.txt就简单分析完毕了。
最后放一下官方的一个链接:https://developer.android.com/studio/projects/add-native-code?hl=zh-cn