這篇文章將會(huì)講解Make,Makefile,cMake的相關(guān)知識(shí),以便能夠在AndroidStudio中使用CMakeLists.txt文件進(jìn)行相關(guān)的配置。
這篇文章的內(nèi)容包含
- 了解make和makefile以及cmake
- 如何對CMakeList.txt進(jìn)行配置
- 如何引入源文件
- 如何引入外部的靜態(tài)庫和動(dòng)態(tài)庫
- 使用file和aux_source_directory添加所有的源文件
- 添加頭文件
- 引入其它的CMakeList
- 引入外部動(dòng)態(tài)庫時(shí)存在的問題
- 依賴庫在5.0和6.0的差異以及如何使用
- 如何對app下的build.gralde進(jìn)行配置
Make
- Make是一種工具,用于控制從程序的源文件生成程序的可執(zhí)行文件和其他非源文件。
- 需要一個(gè)名為makefile的文件來告訴make該怎么做。通常,makefile會(huì)告訴make如何編譯和鏈接程序。
- 默認(rèn)情況下,當(dāng)make查找makefile時(shí),它將按順序嘗試以下名稱:
GNUmakefile,makefile和Makefile文件。如果make找不到這些名稱,則不使用任何makefile。 - 根據(jù)更改的源文件,自動(dòng)確定需要更新的文件。如果一個(gè)非源文件依賴于另一個(gè)非源文件,它還會(huì)自動(dòng)確定更新文件的正確順序。如此一來,如果更改了一些源文件,然后運(yùn)行Make,則不需要重新編譯所有程序。它僅更新直接或間接依賴于更改的源文件的那些非源文件。
-
Make不限于任何特定語言。對于程序中的每個(gè)非源文件,makefile指定用于計(jì)算它的shell命令。這些Shell命令可以運(yùn)行編譯器以生成目標(biāo)文件,鏈接器以生成可執(zhí)行文件, ar以更新庫,或運(yùn)行TeX或Makeinfo來格式化文檔。
Makefile
- 無論是c、c++首先要把源文件編譯成中間代碼文件,在Windows下也就是 .obj 文件,UNIX下是
.o文件,即 Object File,這個(gè)動(dòng)作叫做編譯(compile),然后再把大量的Object File合成執(zhí)行文件或者靜動(dòng)態(tài)庫,這個(gè)動(dòng)作叫作鏈接(link)。 - 一個(gè)工程中的源文件不計(jì)數(shù),其按類型、功能、模塊分別放在若干個(gè)目錄中,
makefile定義了一系列的規(guī)則來指定,哪些文件需要先編譯,哪些文件需要后編譯,如何進(jìn)行鏈接等等操作。 -
makefile 就是“自動(dòng)化編譯”,告訴make命令如何編譯和鏈接,即make工具的配置腳本。
-? 當(dāng)然,也可以使用別的文件名來書寫Makefile,比如:“Make.Linux”,“Make.android”。這樣在使用時(shí)候就需要make -f XX或者make --file XX。
cMake
- CMake是旨在構(gòu)建,測試和打包軟件的開源,
跨平臺(tái)工具系列。Cmake 并不直接建構(gòu)出最終的軟件,而是產(chǎn)生其他工具的腳本(如Makefile ),然后再依這個(gè)工具的構(gòu)建方式使用。 - CMake是一個(gè)跨平臺(tái)的構(gòu)建工具,可以用簡單的語句來描述所有平臺(tái)的安裝(編譯過程)。能夠輸出各種各樣的makefile或者project文件。Cmake 并不直接建構(gòu)出最終的軟件,而是產(chǎn)生其他工具的腳本(如Makefile ),然后再依這個(gè)工具的構(gòu)建方式使用。
CMake在AndroidStudio中的使用
Android Studio利用CMake生成的是ninja,ninja是一個(gè)小型的關(guān)注速度的構(gòu)建系統(tǒng)。我們不需要關(guān)心ninja的腳本,知道怎么配置cmake就可以了。從而可以看出cmake其實(shí)是一個(gè)跨平臺(tái)的支持產(chǎn)出各種不同的構(gòu)建腳本的一個(gè)工具。
CMake的腳本名默認(rèn)是CMakeLists.txt。
CMakeLists.txt配置
-
cmake_minimum_required指定CMake支持版本
cmake_minimum_required(VERSION 3.4.1)
- add_library
1.add_library的第一個(gè)作用以源文件的形式導(dǎo)入靜態(tài)庫和動(dòng)態(tài)庫
add_library(
native-lib2
SHARED
native-lib.cpp)
target_link_libraries( native-lib2 )
native-lib2:變量名字,這個(gè)名字隨便起
SHARED:動(dòng)態(tài)庫STATIC:靜態(tài)庫
native-lib:源文件
使用:
System.loadLibrary("native-lib2");
2.add_library的第二個(gè)作用從外部導(dǎo)入靜態(tài)庫或者動(dòng)態(tài)庫:
1)從外部導(dǎo)入靜態(tài)庫
add_library(
native-lib2
SHARED
src/main/cpp/native-lib.cpp)
add_library(
Test2
STATIC
IMPORTED)
set_target_properties(Test2 PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/src/main/cpp/${ANDROID_ABI}/libTest.a)
target_link_libraries( Test2 )
target_link_libraries(
native-lib2
Test
)
IMPORTED表示我們這一個(gè)靜態(tài)庫是以導(dǎo)入的形式添加進(jìn)來的(預(yù)編譯靜態(tài)庫),那如何導(dǎo)入呢?通過設(shè)置目標(biāo)屬性方法set_target_properties,CMAKE_SOURCE_DIR表示當(dāng)前CMakeLists.txt的路徑,如果需要編譯出過個(gè)平臺(tái)的so的時(shí)候,就要使用ANDROID_ABI,它可以動(dòng)態(tài)的獲取是哪個(gè)路徑下的so文件。
注意: native-lib2和Test的順序不能調(diào)到,要把源文件native-lib2放在前面。
使用:
System.loadLibrary("Test2");
2)從外部導(dǎo)入動(dòng)態(tài)庫
從外部導(dǎo)入動(dòng)態(tài)庫和靜態(tài)庫有點(diǎn)區(qū)別,so文件需要放到j(luò)niLibs目錄下,否則不會(huì)打包到app中。
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp)
add_library(
Test
SHARED
IMPORTED)
set_target_properties(Test PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/armeabi-v7a/libTest.so)
target_link_libraries(
native-lib
Test
)
上面的代碼配置只能在6.0以下使用,可以使用下面的辦法來解決:
add_library(
native-lib
SHARED
src/main/cpp/native-lib.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}")
target_link_libraries(
native-lib
Test
)
CMAKE_CXX_FLAGS這個(gè)是 c++的參數(shù) 會(huì)傳給編譯器,只要源文件中有C++的代碼就要使用這個(gè)。CMAKE_C_FLAGS這個(gè)是 c的參數(shù),會(huì)傳給編譯器。-L是查看庫文件。注意:target_link_libraries中的Test不能為其它的名字,因?yàn)椴皇亲兞苛恕?/p>
-findLibrary
NDK中已經(jīng)有一部分預(yù)構(gòu)建庫 ndk庫已經(jīng)是被配置為cmake搜索路徑的一部分,比如
findLibrary(log-lib log)
target_link_libraries(
native-lib
${log-lib} )
也可以直接這樣:
target_link_libraries( native-lib
log )
如果我們想引入外部的庫,就需要使用CMAKE_C_FLAGS或者CMAKE_CXX_FLAGS
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI}")
target_link_libraries(
#我這里的so文件名為:libTest.so
Test
)
注意,這個(gè)Test的名字要和目標(biāo)文件的名字一致。
- 使用file或者aux_source_directory添加所有的源文件
使用file可以添加某個(gè)目錄下所有的源文件
file(GLOB source ${CMAKE_SOURCE_DIR}/*.cpp)
add_library(
native-lib
SHARED
${source})
target_link_libraries(
native-lib
)
#使用這個(gè)庫
System.loadLibrary("native-lib");
使用aux_source_directory可以添加某個(gè)目錄下所有的源文件
#native-lib和CMakeLists.txt在同一目錄下
aux_source_directory( ${CMAKE_SOURCE_DIR}/ source)
#將source這個(gè)變量給到下面
add_library(
native-lib
SHARED
${source})
target_link_libraries(
native-lib
)
#使用這個(gè)庫
System.loadLibrary("native-lib");
${CMAKE_SOURCE_DIR}/為查找CMakeList.txt這個(gè)文件所在的當(dāng)前目錄下的文件,不包括子目錄。
- 引入其它目錄的cmakelist
add_subdirectory(XX目錄)
- 引入頭文件
相當(dāng)于-I(大寫的i)
include_directories(XX目錄)
5.0及以下與6.0及以上的注意事項(xiàng)
存在兩個(gè)動(dòng)態(tài)庫libhello-jni.so 與 libTest.so。
libhello-jni.so依賴于libTest.so (使用NDK下的ndk-depends可查看依賴關(guān)系),則:
java //<=5.0: System.loadLibrary("Test"); System.loadLibrary("hello-jni"); //>=6.0: System.loadLibrary("hello-jni");
除此之外,app下的build.gradle也是非常重要的
android {
defaultConfig {
//指導(dǎo)我們的源文件編譯
externalNativeBuild {
cmake {
cppFlags ""
//你希望編譯你的c/c++源文件,編譯幾種cpu(arm,x86等)
abiFilters "armeabi-v7a"
//abiFilters "arm64-v8a","armeabi-v7a"
}
}
//這里表示打包集中cpu,比如集成了第三方庫,第三方庫提供了arm的,提供了x86的,可以在此處指導(dǎo)打包arm的,生成出來的apk就包含arm的。
ndk{
abiFilters "armeabi-v7a"
//abiFilters "arm64-v8a","armeabi-v7a"
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"http://這里指定CMakeLists.txt文件的路徑
version "3.10.2"
}
}
}