使用AndroidStudio3.4創(chuàng)建一個(gè)C/C++Support的項(xiàng)目,默認(rèn)在app/src/main目錄下會(huì)生成cpp目錄欲低,里面包含CMakeList.txt和native-lib.cpp。下面代碼為CMakeList.txt去掉英文注釋格式化后的內(nèi)容。
#指定cmake最小支持版本
cmake_minimum_required(VERSION 3.4.1)
#添加一個(gè)庫,根據(jù)native-lib.cpp源文件編譯一個(gè)native-lib的動(dòng)態(tài)庫
add_library(
native-lib
SHARED
native-lib.cpp)
#查找系統(tǒng)庫,這里查找的是日志庫,賦值給log-lib
#ndk路徑\platforms\android-21\arch-arm\usr\lib下查找系統(tǒng)庫
find_library(
log-lib
log)
#設(shè)置依賴的庫 (第一個(gè)參數(shù)必須為目標(biāo)模塊, 順序不能換)
target_link_libraries(
native-lib
${log-lib})
CMakeList中的常用命令:
cmake_minimum_required
cmake_minimum_required(VERSION 3.4.1)
指定最低支持的版本,可選,可不寫,如果我們使用了一些高版本特有的命令,那就需要指明最低支持版本
aux_ source_ directory
#.表示當(dāng)前目錄
aux_source_directory(.DIR_SRCS)
查找當(dāng)前目錄所有源文件并將源文件名稱列表保存到DIR_SRCS變量
不能查找子目錄
add_library
添加一個(gè)庫或者導(dǎo)入預(yù)編譯庫
添加一個(gè)庫
添加一個(gè)庫文件,名為<name>。指定STATIC,SHARED,MODULE參數(shù)來指定庫的類型油猫。
STATIC: 靜態(tài)庫;
SHARED: 動(dòng)態(tài)庫;
MODULE:使用dyld的系統(tǒng)有效,若不支持dyld,等同于SHARED
EXCLUDE_FROM_ALL: 表示該庫不會(huì)被默認(rèn)構(gòu)建柠偶。
source1 source2... sourceN:用來指定庫的源文件
格式:
add_ library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_ FROM_ ALL] source1 source2 ...sourceN)
導(dǎo)入預(yù)編譯庫
添加一個(gè)已存在的預(yù)編譯庫情妖,名為<name>。
一般配合set_target_properties使用
格式:
add library (<name>
<SHARED | STATIC | MODULE | UNKNOWN> IMPORTED)
示例:
add library(test SHARED IMPORTED)
set_target_properties (
test #指明目標(biāo)庫名
PROPERTIES IMPORTED_ LOCATION #指明要設(shè)置的參數(shù)
庫路徑/${ANDROID_ ABI}/libtest.so #導(dǎo)入庫的路徑
)
set命令
set用于設(shè)置Cmake的變量,常用舉例:
#設(shè)置可執(zhí)行文件的輸出路徑( EXCUTABLE_OUTPUT_PATH是全局變量)
set ( EXECUTABLE_OUTPUT_PATH [output_path])
#設(shè)置庫文件的輸出路徑 (LIBRARY OUTPUT PATH是全局變量 )
set (LIBRARY_OUTPUT_PATH [output_path])
#設(shè)置C++編譯參數(shù)(CMAKE_CXX_FLAGS是全局變量)
set(CMAKE CXX_FLAGS "-Wall std=c++11" )
#設(shè)置源文件集合( SOURCE_FILES是本地變量即自定義變量)
set ( SOURCE_FILES main. cpp test.cpp ... )
include_directories
設(shè)置頭文件目錄
相當(dāng)于g++選項(xiàng)中的-I參數(shù)
#可以用相對或絕對路徑诱担, 也可以用自定義的變量值
include_directories(./include ${MY_INCLUDE})
add_executable
用于添加可執(zhí)行文件
#第一個(gè)參數(shù)是文件名,第二個(gè)參數(shù)是源文件
add_executable(<name> ${SRC_LIST})
target_link_libraries
將若干庫鏈接到目標(biāo)庫文件
鏈接的順序應(yīng)當(dāng)符合gcc鏈接順序規(guī)則毡证,被鏈接的庫放在依賴它的庫的后面,即如果下面的命令中蔫仙,lib1依賴于lib2, lib2又依賴于lib3料睛,則在.上面命令中必須嚴(yán)格按照(lib1
lib2 lib3的順序排列,否則會(huì)報(bào)錯(cuò)
target_link_libraries(<name> lib1 lib2 lib3)
#如果出現(xiàn)互相依賴的靜態(tài)庫摇邦,CMake會(huì)允許依賴圖中包含循環(huán)依賴恤煞,如:
add library(A STATIC a.c)
add_library(B STATIC b.c)
target_link_libraries(A B)
target_link_libraries(B A)
add_executable(main main.c )
target_tink_libraries (main A)
add_definitions
通常用于添加編譯參數(shù):
#為當(dāng)前路徑以及子目錄的源文件加入由-D引入的define flag
add definitions( -DF00 -DDEBUG ...)
add_subdirectory
如果當(dāng)前目錄下還有子目錄時(shí)可以使用add_subdirectory, 子目錄中也需要包含有
CMakeLists.txt
# sub_dir指定包含CMakeLists.txt和源碼文件的子目錄位置
# binary_dir是輸出路徑,一般可以不指定
add_subdirecroty(sub_dir [binary_dir])
file
文件操作命令,常見用法
使用者中方式添加文件,需要注意,在沒有改動(dòng)CMakeLists.txt文件的情況下,重新編譯會(huì)報(bào)錯(cuò),需要改動(dòng)CMakeLists.txt文件,使其重新編譯,比如添加一個(gè)空格,然后在編譯就會(huì)重新生成makefile文件
#將message寫入filename文件中,會(huì)覆蓋文件原有內(nèi)容
file(WRITE filename "message" )
#將message寫入filename文件中施籍,會(huì)追加在文件末尾
file (APPEND filename "message" )
#從filename文件中讀取內(nèi)容并存儲(chǔ)到var變量中居扒,如果指定了numBytes和offset,
#則從offset處開始最多讀numBytes個(gè)字節(jié)丑慎,另外如果指定了HEX參數(shù)苔货,則內(nèi)容會(huì)以十六進(jìn)制形式存儲(chǔ)在var變量中
file (READ filename var [LIMIT numBytes] [OFFSET offset] [HEX] )
#重命名文件
file (RENAME <oldname> <newname> )
#刪除文件,等于rm命令
file(REMOVE [file ...])
#遞歸的執(zhí)行刪除文件命令立哑,等于rm -r
file(REMOVE RECURSE [filel ...])
#根據(jù)指定的url下載文件
# timeout超時(shí)時(shí)間; 下載的狀態(tài)會(huì)保存到status中; 下載日志會(huì)被保存到log; sum指定所下載文件預(yù)期的MD5值, 如果指定會(huì)自動(dòng)進(jìn)行比對姻灶,
#如果不一致铛绰,則返回一個(gè)錯(cuò)誤; SHOW_PROGRESS, 進(jìn)度信息會(huì)以狀態(tài)信息的形式被打印出來
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum] [SHOW_PROGRESS])
#創(chuàng)建目錄
file(MAKE_DIRECTORY [dir1 dir2 ...])
#會(huì)把path轉(zhuǎn)換為以unix的/開頭的cmake風(fēng)格路徑,保存在result中
file(TO_CMAKE_PATH path result)
#它會(huì)把cmake風(fēng)格的路徑轉(zhuǎn)換為本地路徑風(fēng)格: windows 下用"\"产喉,而unix下用”/"
file(TO_NATIVE_PATH path result )
#將會(huì)為所有匹配查詢表達(dá)式的文件生成個(gè)文件list, 并將該list存儲(chǔ)進(jìn)變量variable里捂掰,如果一個(gè) 表達(dá)式指定了RELATIVE敢会,返回的結(jié)果
#將會(huì)是相對于給定路徑的相對路徑,查詢表達(dá)式例子: *.cxx, *.vt?
# NOTE: 按照官方文檔的說法这嚣,不建議使用file的GL0B指令來收集1程的源文件
file(GLOB variable [RELATIVE path] [globbing expressions]... )
set_directory_properties
設(shè)置某個(gè)路徑的一種屬性
prop1, prop2代表屬性鸥昏,取值為:INCLUDE_DIRECTORIES
LINK_DIRECTORIES
INCLUDE_REGUL AR_EXPRESSION
ADDITIONAL_MAKE_CLEAN_FILES
set_directory_properties (PROPERTIES prop1 value1 prop2 value2)
set_property
在給定的作用域內(nèi)設(shè)置一個(gè)命名的屬性
PROPERTY參數(shù)是必須的
第一個(gè)參數(shù)決定了屬性可以影響的作用域:
GLOBAL:全局作用域
DIRECTORY:默認(rèn)當(dāng)前路徑,也可以用[dir]指定路徑(可使用相對路徑/絕對路徑指定)
TARGET:目標(biāo)作用域,可以是0個(gè)或多個(gè)已有目標(biāo)
SOURCE:源文件作用域姐帚,可以是0個(gè)或多個(gè)源文件(源文件屬性只對同目錄下的CMakeLists中的目標(biāo)可見)
TEST:測試作用域吏垮,可以是0個(gè)或多個(gè)已有的測試
CACHE:必須指定0個(gè)或多個(gè)cache中已有的條目
set_property (<GL0BAL
| DIRECTORY [dir]
| TARGET [target ...]
| SOURCE [src1...]
| TEST [test1...]
| CACHE [entry1 ...] >
[APPEND]
PROPERTY <name> [value ...]
多個(gè)源文件處理
如果源文件很多,把所有文件一個(gè)個(gè)加入很麻煩罐旗,可以使用aux_source_directory命令或file命令膳汪,會(huì)查找指定目錄下的所有源文件,然后將結(jié)果存進(jìn)指定變量名九秀。
cmake_minimum_required (VERSION 3.4.1)
#查找當(dāng)前目錄所有源文件并將名稱保存到DIR_SRCS 變量
#不能查找子目錄
aux_source_directory(. DIR_SRCS)
#也可以使用
# file(GLOB DIR_ SRCS *.c *.cpp )
add_Library(
native-lib
SHARED
${DIR_SRCS})
多目錄多源文件處理
- 主目錄中的CMakeLists.txt中添加add_subdirectory(child)命令遗嗽,指明本項(xiàng)目包含一個(gè)子項(xiàng)目child。并在target_link_libraries指明本項(xiàng)目需要鏈接一個(gè)名為child的庫鼓蜒。
- 子目錄child中創(chuàng)建CMakeLists.txt,這里child編譯為共享庫痹换。
cmake_minimum_required (VERSION 3.4.1)
aux_source_directory(. DIR_SRCS)
#添加 child 子目錄下的cmakelist
add_subdirectory(child)
add_library(
native-lib
SHARED
${DIR_SRCS} )
target_link_libraries (native-lib child)
#-----------------------------------------
#child目錄下的CMakeLists.txt:
cmake_ minimum_required (VERSION 3.4.1)
aux_ source_ directory(. DIR_LIB_SRCS)
add_library(
child
SHARED
${DIR_LIB_SRCS})
添加預(yù)編譯庫(Android6.0版本以前)
- 假設(shè)我們本地項(xiàng)目引用了libimported-lib.so。
- 添加add_library命令都弹, 第一個(gè)參數(shù)是模塊名娇豫,第二個(gè)參數(shù)SHARED表示動(dòng)態(tài)庫,STATIC表示靜態(tài)庫缔杉,第三個(gè)參數(shù)IMPORTED表示以導(dǎo)入的形式添加锤躁。
- 添加set_target_properties命令設(shè)置導(dǎo)入路徑屬性。
4.將import-lib添加到target_link_libraries命令參數(shù)中或详,表示native-lib需要鏈接imported-lib模塊
cmake_minimum_required(VERSION 3.4.1)
#使用IMPORTED 標(biāo)志告知CMake 只希望將庫導(dǎo)入到項(xiàng)目中
#如果是靜態(tài)庫則將shared改為static
add_library( imported-lib
SHARED
IMPORTED )
#參數(shù)分別為:庫系羞、屬性、導(dǎo)入地址霸琴、庫所在地址
set_target_properties(
imported-lib
PROPERTIES
IMPORTED_LOCATION
<路徑>/libimported-lib. so)
aux_source_directory(. DIR_SRCS)
add_library(
native-lib
SHARED
${DIR_SRCS} )
target_link_libraries (native-lib imported-lib)
添加預(yù)編譯庫(Android6.0版本以后)
在Android 6.0及以上版本椒振,如果使用上述的方法添加預(yù)編譯動(dòng)態(tài)庫的話,會(huì)有問題梧乘。我們可以使用另外種方式來配置澎迎。
# set命令定義一個(gè)變量
# CMAKE_C_FLAGS: c的參數(shù),會(huì)傳遞給編譯器
#如果是c++文件,需要用CMAKE_CXX FLAGS
# -L: 庫的查找路徑
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L [SO所在目錄]")
添加頭文件目錄
為了確保CMake可以在編譯時(shí)定位頭文件选调,使用include_directories, 相當(dāng)于g++選項(xiàng)中的-l參數(shù)夹供。這樣就可以使用#include<xx.h>,否則需要使用 #include"path/xx.h"
cmake_minimum_required(VERSION 3. 4.1)
#設(shè)置頭文件目錄
include_directories(<文件目錄>)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L [SO所在目錄]")
aux_source_directory(. DIR_SRCS)
add_library(
native-lib
SHARED
${DIR_ SRCS})
target_link_libraries (native-lib imported-lib)
Build.gradle配置
可以在gradle中使用arguments設(shè)置一些配置
android{
defaultConfig{
cmake{
// 使用的編譯器clang/gcc
// cmake默認(rèn)就是 gnustl_static
arguments "-DANDROID_TOOLCHAIN=clang","-DANDROID_STL=gnustl_static"
// 指定cflags和cppflags,效果和cmakelist使用一樣
cFlags ""
cppFlags ""
// 指定需要編譯的cpu架構(gòu)
abiFilters "armeabi-v7a"
}
}
externalNativeBuild{
cmake{
// 指定CMakeLists.txt文件相對當(dāng)前build.gradle的路徑
path "xxx/CMakeLists.txt"
}
}
}
集成fomd為例
官網(wǎng):https://www.fmod.com/
SDK下載頁面:https://www.fmod.com/download(需要注冊登錄才能下載)
第一步: 集成頭文件,so文件
將下載的fmodstudioapi20000android.tar.gz 解壓仁堪,找到 api/core
目錄下的inc
文件夾哮洽,其中fmod的頭文件,lib是fmod預(yù)編譯好的so和jar文件弦聂。將inc
整個(gè)文件夾copy到項(xiàng)目的cpp文件夾下:
然后在
CMakeLists
文件中,設(shè)置頭文件目錄如下:
#設(shè)置頭文件路徑
#這里通過Cmake預(yù)置變量CMAKE_SOURCE_DIR拿到CMakeLists當(dāng)前路徑
#這里就是src/main/cpp
include_directories(${CMAKE_SOURCE_DIR}/inc)
然后在項(xiàng)目的main文件夾下,新建文件夾jniLibs
,將 api/core/lib
下的所有文件夾都copy到jniLibs
下:
修改module的build.gradle
文件中的defaultConfig
:
defaultConfig {
applicationId "com.code.cmakedemo"
minSdkVersion 14
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
abiFilters "x86" //本地庫的cpu架構(gòu) (模擬器所以選了x86)
}
}
ndk{
abiFilters "x86" //三方so庫的cpu架構(gòu) (模擬器所以選了x86)
}
}
然后修改CMakeLists文件,將libfomd.so
和libfomdL.so
添加到依賴庫里:
#設(shè)置第三方so庫的路徑
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}}")
#設(shè)置依賴的庫 (第一個(gè)參數(shù)必須為目標(biāo)模塊, 順序不能換)
target_link_libraries(
native-lib
fmod
fmodL
${log-lib})
這樣就配置完成了,然后可以在native-lib.cpp
中導(dǎo)入和使用fmod
庫