29 CMake 知识点 - Android Studio (笔记)

187 阅读3分钟

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(列表名 值12 ... 值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里面去
        )

在这里插入图片描述
在这里插入图片描述