前言
CMake是一个开源的、跨平台的构建工具。
在Android NDK(Native Development Kit)开发中,编译C/C++代码的方式,主要有两种:ndk-build、CMake。在Android源码中,你会频繁看见前者。而后者,则是Android Studio创建包含C/C++代码的项目时,默认使用的构建工具。CMake可以配合Gradle,完成整个项目的构建。
摘要
本文主要内容如下:
代码
示例代码:Java2Cpp
创建Native项目
Android Studio可以创建包含C/C++代码的项目:
- 打开Studio:
File
->New
->New Project
:
- 选择
Native C++
,然后一路Next即可:
如果是想在已有项目上,新增一个Native模块也可以:
File
->New
->New Module
:
Native项目的不同
Native项目与普通Android项目的差异如下:
build.gradle的不同
在/module/build.gradle
下,会新增配置:
android {
defaultConfig {
externalNativeBuild {
cmake {
cppFlags ''
}
}
}
externalNativeBuild {
cmake {
//CMake配置文件所在路径
path file('src/main/cpp/CMakeLists.txt')
version '3.10.2'
}
}
}
目录结构的不同
- 在
main
下,多一个cpp
目录:CMakeLists.txt
是CMake的配置文件。*.cpp
是C++源文件。
- 通过
Make Project
编译项目后,在/module/build/intermediates/cmake/debug/obj
下,会出现so文件(so文件即动态链接库,是由C/C++代码编译出来的):
CMake语法
- 设置CMake要求的最小版本号
cmake_minimum_required(VERSION 3.10.2)
- 声明项目名称
project("java2cpp")
- 创建并命名一个库,设置它为
STATIC
或者SHARED
,并且提供源码文件(.cc、.cpp等)的相对路径。可以同时定义多个库。CMake会进行构建,然后Gradle会自动打包动态库进apk中。
add_library(
# 设置库名称
java2cpp
# 设置库为动态库
SHARED
# 提供源文件的相对路径,可以设置多个源文件相对路径
native-lib.cpp)
注意事项:
- 库类型有两种:
- SHARED:动态库,最终生成的库文件是
*.so
,如libjava2cpp.so
。 - STATIC:静态库,最终生成的库文件是
*.a
,如libjava2cpp.a
。
- SHARED:动态库,最终生成的库文件是
如果是要生成静态库,需要修改一下bild.gradle
的配置:
externalNativeBuild {
cmake {
cppFlags ''
//增加这一行
targets "java2cpp"
}
}
一般来说,我们使用动态库即可。想了解动态库、静态库相关,可参考:C++静态库与动态库。
- 源文件路径
add_library
中的native-lib.cpp
不是指文件名,而是文件相对路径。相对,是相对CMakeLists.txt
而言的。如果两者的目录布局如下:
main
├── cpp
│ └──native-lib.cpp
└── CMakeLists.txt
则native-lib.cpp
需要更改为cpp/native-lib.cpp
- 源文件路径添加问题
每次新增.cpp
,都要在add_library里面声明该源文件的路径。操作有点繁琐。可以通过aux_source_directory
或者file
引用目录下的所有源文件:
file(GLOB_RECURSE UTIL_SRC util/*.cpp)
aux_source_directory(. DIR_SRC)
#使用
add_library(
java2cpp
SHARED
${DIR_SRC}
${UTIL_SRC})
aux_source_directory
:会包括指定目录的所有源文件,但不包括子目录。
file
:不仅当前目录,还会包括子目录的所有源文件。
- 导入C/C++头文件
include_directories(
//相对路径
include
)
include_directories是会递归搜索include
目录下的子目录的。比如,下图的media、util目录里的头文件都会被搜索到:
include
├── media
└── util
- 链接其他库文件
如果你的库文件,依赖于其他库时,你需要声明相关链接的库。这些库可以是动态库,也可以是静态库。可以是第三方库,也可以是Android系统库。
- 链接Android系统库
# 搜索一个指定的预构建的库,并且保存该库的路径为一个变量,如log-lib。
# 因为CMake的搜索路径里,默认包含了系统库的路径,所以我们只需要声明NDK库的名称,如log。
find_library(
# 设置变量的名字
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
# 指定你想要CMake定位的NDK库的名字
log)
target_link_libraries(
# 指定目标库
java2cpp
# 链接log库到目标库中
${log-lib})
- 链接第三方库
在项目的libs目录下,有两个第三方库:liba.so
、libb.a
:
#设置一下编译选项,把libs目录加入到库的搜索路径中
#CMAKE_CURRENT_SOURCE_DIR是指CMakeLists.txt所在目录
#CMAKE_ANDROID_ARCH_ABI是指Android CPU的架构类型
set(CMAKE_CXX_FLAGS " -L${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${CMAKE_ANDROID_ARCH_ABI}")
target_link_libraries(
java2cpp
${log-lib}
a
b
)