1. 概述
如果工程代码比较小, 所有的 C/C++ 代码放在一个 CMake 模块里问题不大. 但是随着功能的增加, 可能会拆分模块来管理, 例如一个加密模块, 一个音频处理模块. 或者为了便于管理引入第三方的静态库, 而进行模块拆分.
一种可行简单的办法就是直接分散到每个一个 Gradle Module 当中, 这种方案不讨论, 我们仅讨论全部 C/C++ 模块放到一个 Gradle Module, 最终入下图所示:
AndroidStudio 本地模块
目录规划
在写代码之前, 我们需要规划我们的目录, 这样才能做到有条不紊. 按照 AS 自身做法, 我们依然把所有的 C/C++ 代码放到 cpp 目录当中, 例子中, 会有三个模块: sqlite3(第三方源码),openssl(第三方预编译的静态库),testlib(自己的模块), 目录结构如下:
目录结构
CMakeLists.txt 的组织
根 CMakeLists.txt
有多个模块, 那么需要多个 CMakeLists.txt 来进行组织, 首先是模块根目录下 (注意是模块根目录)CMakeLists.txt, 该文件主要是设定一些基础参数, 并且引入子模块.
文件路径: d:\work\AndroidMultiCMakeModule\app\CMakeLists.txt
内容:
#Sets the minimum version of CMake required to build the native library.cmake_minimum_required(VERSION 3.4.1)#添加include目录,
在C / C++中的include指令能找到对应的头文件#该命令类似java的classpath,
不用的地方的是,
它指示的是头文件,
仅包含类 / 函数等声明include_directories(src / main / cpp) include_directories(src / main / cpp / sqlite3) include_directories(src / main / cpp / openssl / include)#添加导入的库目标,
方便后续添加依赖add_library(openssl_crypto STATIC IMPORTED)#指示该库文件的路径set_target_properties(openssl_crypto PROPERTIES IMPORTED_LOCATION $ {
CMAKE_SOURCE_DIR
}
/src/main / cpp / openssl / $ {
ANDROID_ABI
}
/libcrypto.a)
add_library(openssl_ssl STATIC IMPORTED)
set_target_properties(openssl_ssl
PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src / main / cpp / openssl / $ {
ANDROID_ABI
}
/libssl.a)
# 添子项目的目录
add_subdirectory(src/main / cpp / sqlite3) add_subdirectory(src / main / cpp / testlib)
比较关键的就是 add_subdirectory, 该指令会寻找指定目录下的 CMakeLists.txt
子项目的 CMakeLists.txt
子项目的 CMakeLists.txt 相对来就比较简单, 就是添加源码, 设定其他编译参数一类的.
sqlite3 子模块
project(sqlite)
# 添加静态库
add_library(sqlite_static STATIC sqlite3.c)
testlib 子模块
project(testlib)
# 添加动态库
add_library(testlib SHARED testlib.cpp)
# 为该动态库添加要链接的库
target_link_libraries(testlib sqlite_static openssl_crypto openssl_ssl)
sync 之后, 我们会看到 AS 的工程窗口显示出 C/C++ 模块如下图:
image.png
直接列出了全部引用的 CMakeLists.txt 和 C/C++ 模块.
我们的 TestLib 引用了 sqlite 和 openssl 两个模块, 写代码实测一下:
testlib.cpp
#include <jni.h>
#include <sqlite3.h>
#include <openssl/crypto.h>
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_AndroidMultiCmakeModule_TestLib_sqlite3Version(
JNIEnv *env,
jobject /* this */) {
return env->NewStringUTF(SQLITE_VERSION);
}
extern "C"
JNIEXPORT jstring
JNICALL
Java_com_example_AndroidMultiCmakeModule_TestLib_openSSLVersion(
JNIEnv *env,
jobject /* this */) {
char tmp[256] = {0};
sprintf(tmp, "openssl: %d", OpenSSL_version_num());
return env->NewStringUTF(tmp);
}
TestLib.java 代码:
class TestLib {
public static native String sqlite3Version();
public static native String openSSLVersion();
static {
System.loadLibrary("testlib");
}
}
MainActivity.kt 代码:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle ? ) {
super.onCreate(savedInstanceState) setContentView(R.layout.activity_main)
// Example of a call to a native method
sample_text.text = "sqlite:" + TestLib.sqlite3Version() + "openssl:" + TestLib.openSSLVersion()
}
}
最终运行结果:
image.png
这说明, 我们的 testlib 模块, 正常调用了其他两个 native 模块.
来源: http://www.jianshu.com/p/457e4125acd8