Android Ndk 學習筆記(目錄)
# 最低支援的版本,注意:這裡并不能代表最終的版本,最終版本在app.build.gradle中設定的
cmake_minimum_required(VERSION 3.10.2)
build.gradle 中是cmake 的版本
# 目前工程名,以前的舊版本,是沒有設定的,這個可以設定,也可以不設定
project("ndk28_cmake")
# 批量導入 cpp c源檔案
# file 可以定義一個變量 SOURCE, GLOB(使用GLOB從源樹中收集源檔案清單,就可以開心的 *.cpp *.c *.h)
# https://www.imooc.com/wenda/detail/576408
file(GLOB SOURCE *.cpp *.c *.h *.hpp)
# 添加一個庫(動态庫SHARED,靜态庫STATIC)
add_library(native-lib # 庫的名字 ---> libnative-lib.so
SHARED # 動态庫
# cpp的源檔案:把cpp源檔案編譯成 libnative-lib.so 庫
${SOURCE}
)
# 查找一個 NDK工具中的 動态庫(liblog.so)
# 思考:我如何知道 哪些庫是可以寫的,你怎麼知道些一個log就可以?
# 答:請檢視 D:\Android\Sdk\ndk\21.4.7075529\build\cmake\system_libs.cmake
# 思考:D:\Android\Sdk\ndk\21.0.6113669\toolchains\llvm\prebuilt\windows-x86_64\sysroot\usr\lib\arm-linux-androideabi\16\liblog.so
# 答:你怎麼知道是在 21.4.7075529?,arm-linux-androideabi?,16?
# 答:?1(因為local.properties知道了NDK版本,或者是你目前的NDK版本)
# 答:?2(因為我的手機是arm32的 是以 == arm-linux-androideabi 而且還我運作過)
# 答:?3(因為 minSdkVersion 16)
find_library(log-lib
log )
# native-lib是我們的總庫,也就是我們在 apk/lib/libnative-lib.so
# 然後 把log庫連結到 總庫中去,總庫的cpp代碼就可以使用 android/log.h的庫實作代碼了
target_link_libraries(native-lib # 被連結的總庫
${log-lib} # 連結的具體庫
# getndk
)
# TODO CMake變量
# 聲明變量:set(變量名 變量值)
set(var 666)
# 引用變量:message 指令用來列印
message("var = ${var}")
# CMake中所有變量都是string類型。可以使用set()和unset()指令來聲明或移除一個變量
# 移除變量
unset(var)
message("my_var = ${var}") # 會取不到值,因為被移除了
# TODO CMake清單(lists)
# 聲明清單:set(清單名 值1 值2 ... 值N) 或 set(清單名 "值1;值2;...;值N")
set(list_var 1 2 3 4 5) # 字元串清單呢? CMake中所有變量都是string類型
# 或者
set(list_var2 "1;2;3;4;5") # 字元串清單呢? CMake中所有變量都是string類型
message("list_var = ${list_var}")
message("list_var2 = ${list_var2}")
# TODO CMake流程控制-條件指令
# true(1,ON,YES,TRUE,Y,非0的值)
# false(0,OFF,NO,FALSE,N,IGNORE,NOTFOUND)
set(if_tap OFF) # 定義一個變量if_tap,值為false
set(elseif_tap ON) # 定義一個變量elseif_tap,值為ture
if(${if_tap})
message("if")
elseif(${elseif_tap})
message("elseif")
else(${if_tap}) # 可以不加入 ${if_tap}
message("else")
# endif(${if_tap}) # 結束if
endif() # 結束if 可以不加
# 注意:elseif和else部分是可選的,也可以有多個elseif部分,縮進和空格對語句解析沒有影響
# TODO CMake流程控制-循環指令
set(a "")
# a STREQUAL "xxx"(a等不等xxx,不等于)
# NOT == !
while(NOT a STREQUAL "xxx")
set(a "${a}x")
message(">>>>>>a = ${a}")
endwhile()
#[[ 注意:
break()指令可以跳出整個循環
continue()可以繼續目前循環
]]
foreach(item 1 2 3)
message("1item = ${item}")
endforeach(item) # 結束for
foreach(item RANGE 2) # RANGE 預設從0開始, 是以是:0 1 2
message("2item = ${item}")
endforeach(item)
foreach(item RANGE 1 6 2) # 1 3 5 每次跳級2
message("3item = ${item}")
endforeach(item)
set(list_va3 1 2 3) # 清單
# foreach(item IN LISTS ${list_va3}) 沒有報錯,沒有循環
foreach(item IN LISTS list_va3)
message("4item = ${item}")
endforeach(item)
# TODO CMake自定義函數 Shell的函數很類似
#[[
ARGC:表示傳入參數的個數
ARGV0:表示第一個參數,ARGV1、ARGV2以此類推即可
ARGV:表示所有參數
]]
function(num_method n1 n2 n3)
message("call num_method method")
message("n1 = ${n1}")
message("n2 = ${n2}")
message("n3 = ${n3}")
message("ARGC = ${ARGC}")
message("arg1 = ${ARGV0} arg2 = ${ARGV1} arg3 = ${ARGV2}")
message("all args = ${ARGV}")
endfunction(num_method)
num_method(1 2 3) # 調用num_method函數
# 靜态庫和動态庫本質
// AS gradle:3.x 舊版本沒有任何問題
// 新版本的才有 gradle:4.2.0,自動去尋找jniLibs檔案夾 處理和優化 ,舊版本沒有任何問題
// 編譯報錯: If you are using jniLibs and CMake IMPORTED targets, see
// 解決方案如下:
// https://blog.csdn.net/qq_33750826/article/details/107518573
// 在子產品的build.gradle中設定第三方庫的加載路徑:
// 在gradle plugln 4.0開始,無需指定第三庫加載路徑,gradle自動會幫助我們尋找,否則會出現以下錯
sourceSets.main.jniLibs.srcDirs = ['libs']
# 批量導入 cpp c源檔案
file(GLOB SOURCE ${CMAKE_SOURCE_DIR}/cpp/*.cpp ${CMAKE_SOURCE_DIR}/cpp/*.c)
# TODO 方式一:推薦的方式
#[[
# 第一步:導入fmod頭檔案
include_directories("${CMAKE_SOURCE_DIR}/cpp/inc")
# 第二步:導入庫檔案 (方式一)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/jniLibsaaa/${CMAKE_ANDROID_ARCH_ABI}")
# 第三步連結到總庫中去
target_link_libraries( # native-lib是我們的總庫
native-lib # 被連結的總庫
log # 自動尋找 # 具體的庫 連結到 libnative-lib.so裡面去
fmod # 具體的庫 連結到 libnative-lib.so裡面去
fmodL # 具體的庫 連結到 libnative-lib.so裡面去
)
]]
# TODO 方式二:以前更多使用的方式,老程式員使用的方式
#[[
# 第一步:導入fmod頭檔案
include_directories("${CMAKE_SOURCE_DIR}/cpp/inc")
# 第二步:導入庫檔案 (方式二)
add_library(fmod SHARED IMPORTED)
set_target_properties(fmod PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/jniLibsaaa/${CMAKE_ANDROID_ARCH_ABI}/libfmod.so)
add_library(fmodL SHARED IMPORTED)
set_target_properties(fmodL PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/jniLibsaaa/${CMAKE_ANDROID_ARCH_ABI}/libfmodL.so)
# 第三步連結到總庫中去
target_link_libraries( # native-lib是我們的總庫
native-lib # 被連結的總庫
log # 自動尋找 # 具體的庫 連結到 libnative-lib.so裡面去
fmod # 具體的庫 連結到 libnative-lib.so裡面去
fmodL # 具體的庫 連結到 libnative-lib.so裡面去
)
]]
## OFF=0=false ON=1=true
# set(isSTATIC OFF)
set(isSTATIC ON)
if(${isSTATIC})
# 導入靜态庫
add_library(getndk STATIC IMPORTED)
# 開始真正導入 靜态庫 System.loadLibrary("getndk"); // 如果是動态庫,這裡需要加載,否則注釋
set_target_properties(getndk PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/cpp/libgetndk.a)
message("isSTATIC == static")
else(${isSTATIC})
# 導入動态庫
add_library(getndk SHARED IMPORTED)
# 開始真正導入 動态庫 System.loadLibrary("getndk"); // 如果是動态庫,這裡需要加載,否則注釋
set_target_properties(getndk PROPERTIES
IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/jniLibsaaa/${CMAKE_ANDROID_ARCH_ABI}/libgetndk.so)
message("isSTATIC == shared")
endif(${isSTATIC})
#引入get子目錄下的CMakeLists.txt
add_subdirectory(${CMAKE_SOURCE_DIR}/cpp/libget)
#引入count子目錄下的CMakeLists.txt
add_subdirectory(${CMAKE_SOURCE_DIR}/cpp/libcount)
target_link_libraries( # native-lib是我們的總庫
native-lib # 被連結的總庫
log # 自動尋找 # 具體的庫 連結到 libnative-lib.so裡面去
get # 具體的庫 連結到 libnative-lib.so裡面去
count # 具體的庫 連結到 libnative-lib.so裡面去
)