CMake
Customize C++ Support的两个选择
- Exceptions Support:启用C++异常处理的支持。
- Runtime Type Information Support(RTTI):运行时类型识别。能够给通过基类的指针或者引用来检索其所指对象的实际类型。
android {
externalNativeBuild {
cmake {
cppFlags "-frtti -fexceptions"
}
}
}
创建C模块
创建C代码源文件
创建CMmake脚本文件
如果您的原生源文件还没有CMake构建脚本,则您需要自行创建一个并包含适当的CMake命令。CMake构建脚本是一个纯文本文件,您必须将其命名为CMakeLists.txt。
在CMakeLists文件中添加CMake命令,具体为:
cmake_minimum_required
设置最小需要的CMake的版本。低于最小版本的就会报错。
cmake_minimum_required(VERSION major.minor[.patch[.tweak]][FATAL_ERROR])
// 实例
cmake_minimum_required(VERSION 3.4.1)
add_library
添加名称为<name>
的目标库,目标库是由source1 [source2 ...]
生成的。
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
source1 [source2 ...])
// 实例
add_library( # Sets the name of the library.
guard-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
guard-lib.c
my.cpp
)
include_directories
它是和add_library
配合使用的,告知编译器,编译时使用的源文件的文件路径。这样的作用是确保了CMake可以在编译时定位到.h文件。(当然,如果不加这个字段,可以直接在add_library
里明确地指定)
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
添加原生库
Android NDK本身已经提供了一套原生的API和库,开发者可以直接去使用。
预构建的NDK库是已经存在于Android平台上的,因此无需再构建或者打包到APK中【因此,添加原生库的依赖不会加到APK包的大小】。
同时,NDK预构建库已经是CMake搜索路径的一部分,因此在使用的时候都不需要指定原生库的位置,只需要库的名称即可,并关联到自己库上。
find_library
该命令实现添加到您的CMake构建脚本中以定位NDK库,并将其路径存储为一个变量。您可以使用此变量在构建脚本的其他部分引用NDK库。
find_library (
<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS path1 [path2 ... ENV var]]
[PATHS path1 [path2 ... ENV var]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[DOC "cache documentation string"]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
// 实例
find_library( # Defines the name of the path variable that stores the
# location of the NDK library.
log-lib
# Specifies the name of the NDK library that
# CMake needs to locate.
log )
target_link_libraries
它的作用是为了确保自己的原生库可以调用到预构建的原生库,如果不产生关联,则无法调用。
其中,<target>
必须是通过add_library()
或者add_executable()
创建的库。
<item>
一般就是预构建的原生库。
target_link_libraries(<target> ... <item>... ...)
// 实例
target_link_libraries( # Specifies the target library.
native-lib
# Links the log library to the target library.
${log-lib} )
直接源码的构建android预设的原生库
NDK 还以源代码的形式包含一些库,您在构建和关联到您的原生库时需要使用这些代码。您可以使用 CMake 构建脚本中的 add_library() 命令,将源代码编译到原生库中。要提供本地 NDK 库的路径,您可以使用 ANDROID_NDK 路径变量,Android Studio 会自动为您定义此变量。
例如:
add_library( app-glue
STATIC
${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c )
# You need to link static libraries against your shared native library.
target_link_libraries( native-lib app-glue ${log-lib} )
使用其他的(非android预设)的原生库
添加预构建库与为 CMake 指定要构建的另一个原生库类似。不过,由于库已经预先构建,您需要使用 IMPORTED 标志告知 CMake 您只希望将库导入到项目中:
add_library( imported-lib
SHARED
IMPORTED )
set_target_properties()
来指定引用库的一些相关的数据。
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
// 实例
set_target_properties( # Specifies the target library.
imported-lib
# Specifies the parameter you want to define.
PROPERTIES IMPORTED_LOCATION
# Provides the path to the library you want to import.
imported-lib/src/${ANDROID_ABI}/libimported-lib.so )
同时,为了确保 CMake 可以在编译时定位您的标头文件,您需要使用 include_directories()
命令,并包含标头文件的路径:
include_directories( imported-lib/include/ )
同时,要将预构建库关联到您自己的原生库,请将其添加到 CMake 构建脚本的target_link_libraries()
命令中:
target_link_libraries( native-lib imported-lib app-glue ${log-lib} )
将Gradle关联到自己的原生库
将Gradle关联到自己的原生库,主要是依赖CMake脚本。
可以通过以下几种方式进行关联:
使用 Android Studio UI
手动配置
建立关联
android {
...
defaultConfig {...}
buildTypes {...}
// Encapsulates your external native build configurations.
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
}
}
}
指定特定的配置:
可以在模块级 build.gradle 文件的 defaultConfig {} 块中配置另一个 externalNativeBuild {} 块,为 CMake 或 ndk-build 指定可选参数和标志。与 defaultConfig {} 块中的其他属性类似,您也可以在构建配置中为每个产品风味flavor重写这些属性。
android {
...
defaultConfig {
...
// This block is different from the one you use to link Gradle
// to your CMake or ndk-build script.
externalNativeBuild {
// For ndk-build, instead use ndkBuild {}
cmake {
// Passes optional arguments to CMake.
arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
// Sets optional flags for the C compiler.
cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
// Sets a flag to enable format macro constants for the C++ compiler.
cppFlags "-D__STDC_FORMAT_MACROS"
}
}
}
buildTypes {...}
productFlavors {
...
demo {
...
externalNativeBuild {
cmake {
...
// Specifies which native libraries to build and package for this
// product flavor. If you don't configure this property, Gradle
// builds and packages all shared object libraries that you define
// in your CMake or ndk-build project.
targets "native-lib-demo"
}
}
}
paid {
...
externalNativeBuild {
cmake {
...
targets "native-lib-paid"
}
}
}
}
}
指定 ABI
android {
...
defaultConfig {
...
externalNativeBuild {
cmake {...}
// or ndkBuild {...}
}
ndk {
// Specifies the ABI configurations of your native
// libraries Gradle should build and package with your APK.
abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a',
'arm64-v8a'
}
}
buildTypes {...}
externalNativeBuild {...}
}
补充
CMake参数配置: https://developer.android.com/ndk/guides/cmake.html#variables