1、什麼是Cmake?
C/C++ 的編譯檔案在不同平台是不一樣的。Unix 下使用 makefile 檔案編譯,Windows 下使用 project 檔案編譯。而 CMake 則是一個跨平台的編譯工具,它并不會直接編譯出對象,而是根據自定義的語言規則(CMakeLists.txt)生成 對應 makefile 或 project 檔案,然後再調用底層的編譯.
谷歌從AndroidStudio2.2以上就添加了Cmake方式來編譯NDK代碼,相較之前複雜的NDK-BUILDE方式,Cmake則簡單很多。
2、什麼是NDK?
NDK全名Native Develop Kit,andriod本地開發工具,是Google開發的一套友善開發者在Android 平台上開發Native 代碼的工具;
使用NDK自帶的工具,可快速對C/C++代碼進行建構、編譯和打包,最終生成動态/靜态庫供開發者使用,且不容易被反編譯;
3、如何導入NDK與Cmake環境?
3.1在Setting的Android SDK中勾選以下配置;

3.2 因為Cmake要用到NDK,是以Android NDK location需要指定本地NDK路徑;
4、如何在已有AS項目中導入Cmake?
4.1導入Cmake相關檔案;
路徑可以自定義,這裡選擇的是"app/src/main/cpp/",其中CMakeLists.txt是Cmake的執行腳本, test-jni.c是Jni檔案,用于編譯生成so庫;
4.2. app工程關聯Cmake
打開app目錄下的build.gradle(見上圖紅框),添加以下語句,使AS工程關聯上Cmake用于編譯;
參考網址: https://www.cnblogs.com/qcjd/p/9324903.html
android{
...
defaultConfig {
...
externalNativeBuild {
cmake {
cppFlags ""
// Passes optional arguments to CMake.//編譯選項,與makefile類似
//arguments "-DANDROID_ARM_NEON=TRUE", "-DANDROID_TOOLCHAIN=clang"
// Sets optional flags for the C compiler.預置C的宏
//cFlags "-D_EXAMPLE_C_FLAG1", "-D_EXAMPLE_C_FLAG2"
// Sets a flag to enable format macro constants for the C++ compiler.預置C++的宏
//cppFlags "-D__STDC_FORMAT_MACROS"
}
}
ndk {//編譯生成哪個CPU平台的庫
abiFilters 'armeabi-v7a','x86_64'
// ARMv5——armeabi
// ARMv7 ——armeabi-v7a
// ARMv8——arm64- v8a
// x86——x86
// MIPS ——mips
// MIPS64——mips64
// x86_64——x86_64
}
}
...
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt') //CMakeLists.txt存放路徑
version "3.10.2"
}
}
...
}
5、Cmake常用文法介紹
# 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)
project(NDK)
###############參考網址:https://www.cnblogs.com/qcjd/p/9324903.html
# ==========================================文法知識(start)=====================================
# 0==================<多檔案編譯生成庫>=============================
#1、 設定多檔案目錄---方法1: (常用)
#1.1查找src/main/cpp目錄下所有以*./c *.cpp檔案并儲存到DIR_SRCS變量裡
file(GLOB DIR_SRCS “src/main/cpp/*.c” “src/main/cpp/*.cpp”)
#1.2不同級目錄下的指定
file(GLOB DIR_SRCS “../src2/main/cpp/*.c” “../src3/main/cpp/*.cpp”)
#1.3如果cpp目錄下還有别的子目錄,但又不想每個子目錄路徑都制定過來,則可以用到遞歸查找
file(GLOB_RECURSE SRC_FILES "src/hello*")#注意:這裡的目錄不能有特殊字元,例如:<SerialPort_c>
#2、設定多檔案目錄---方法2:指定目前目錄下的源檔案,儲存到<DIR_SRCS>變量中
aux_source_directory(. DIR_SRCS)
#3、關聯1或2中的DIR_SRCS變量,生成庫
# # SHARED: 動态庫 STATIC:靜态庫、
add_library(hello-jni SHARED ${DIR_SRCS})
# 制定生成目标(可忽略)
add_executable(mathPowerDemo2 ${ALL_SRCS})
# ==================<引入已有預編譯好的靜态庫/動态庫>=========================
# 1.1、引入已有的預編譯好的靜态庫
# StaticTest 可以随便起名字(原名:libStaticTest.a)
# IMPORTED: 表示靜态庫是以導入的形式添加進來(預編譯靜态庫)
add_library(StaticTest STATIC IMPORTED)
# 1.2、引入已有的預編譯好的動态庫
# SharedTest 可以随便起名字(原名:libSharedTest.so)
# IMPORTED: 表示靜态庫是以導入的形式添加進來(預編譯靜态庫)
add_library(SharedTest SHARED IMPORTED)
# 2.1、設定1.1/1.2中指定的動态庫/靜态庫的導入路徑
# 下面CMAKE_SOURCE_DIR 是系統預定義好的變量,代表目前CMakeLists.txt所在的目錄
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libStaticTest.a)
#下面${ANDROID_ABI}中的ANDROID_ABI應該指各個ABI版本的目錄
# othermodule為庫名稱
set_target_properties(othermodule PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/jniLibs/${ANDROID_ABI}/libothermodule.so)
# 各個ABI版本
# ARMv5——armeabi
# ARMv7 ——armeabi-v7a
# ARMv8——arm64- v8a
# x86——x86
# MIPS ——mips
# MIPS64——mips64
# x86_64——x86_64
# 2.2、設定動态庫的導入路徑
# 下面CMAKE_SOURCE_DIR 是系統預定義好的變量,代表目前CMakeLists.txt所在的目錄
set_target_properties(StaticTest PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/static/armeabi-v7a/libSharedTest.so)
# 3.1 額外頭檔案查找路徑設定 相當于makefile中的-I
include_directories(src/main/include)//本地或者外部庫需要的頭檔案路徑指定
# 3.2 使用其餘CMakeLists.txt配置
# 額外引入src/main/subcmakelist目錄的cmakelist
add_subdirectory(src/main/subcmakelist)
# 3.3 增加指定的宏定義 相當于-D
add_definitions(-D_LINUX -D_ANDROID)
# 4、配置動态庫連結,生成native-lib動态庫需要用到StaticTest log動态或者靜态庫
target_link_libraries( # Specifies the target library.
native-lib
# libTest.so 可以去掉lib與.so
StaticTest
SharedTest
log )
# 動态庫這樣引入沒有版本差異,如果像上面那樣引入會有版本問題
# CMAKE_CXX_FLAGS 會傳給c++編譯器
# CMAKE_C_FLAGS 會傳給c編譯器
# CMAKE_SOURCE_DIR 的值是目前CMakelist.txt所在目錄
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/src/main/jniLibs/armeabi-v7a")
# ===========================================文法知識(end)========================================
# ===========================================使用範本========================================
# 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.
# 配置so庫資訊
add_library( # Sets the name of the library.
# 生成的so庫名稱,此處生成的so檔案名稱是libnative-lib.so
native-lib
# Sets the library as a shared library.
# STATIC:靜态庫,是目标檔案的歸檔檔案,在連結其它目标的時候使用
# SHARED:動态庫,會被動态連結,在運作時被加載
# MODULE:子產品庫,是不會被連結到其它目标中的插件,但是可能會在運作時使用dlopen-系列的函數動态連結
SHARED
# Provides a relative path to your source file(s).
# 資源檔案,可以多個,
# 資源路徑是相對路徑,相對于本CMakeLists.txt所在目錄
src/maind/jni/XJni.c)
# 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.
# android系統每個類型的庫會存放一個特定的位置,而log庫存放在log-lib中
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
# android系統在c環境下打log到logcat的庫
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} )