Android CMake

    CMake是跨平台的构建工具,可以用简单的语句来描述所有平台的安装(编译过程)。能够输出各种各样的makefile或project文件。
    CMake不直接构建出最终的软件,而是产生其他工具的脚本(如makefile的),然后再依据这个工具的构建方式使用。
    AndroidStudio利用CMake生成的是ninja,ninja是一个小型的关注速度的构建系统。
    CMake是一个跨平台的支持产出各种不同的构建脚本的一个工具。

创建一个项目,默认生成的CMakeLists.txt内容

Android CMake_第1张图片

1)最低支持的版本 cmake_minimum_required

# 最低支持的版本,并不是最终的版本,最终版本在 app/build.gradle 中设置的
cmake_minimum_required(VERSION 3.4.1)

Android CMake_第2张图片

2)添加库 add_library

# 默认生成的,导入native-lib源文件
add_library(
        native-lib
        SHARED
        native-lib.cpp)
# 可以写成下方这样
# GLOB 收集源文件列表; 定义一个变量SOURCE
# 添加库  native-lib为库的名字,最终为libnative-lib.so;  
# SHARED为动态库xxx.so,STATIC为静态库xxx.a; 
# ${SOURCE} 为把对应的源文件变异成libnative-lib.so库

file(GLOB SOURCE *.cpp *.c)
add_library(
        native-lib
        SHARED
        ${SOURCE})

3)查找库 find_library / target_link_libraries

# 查找动态库log,并把它命名为log-lib别名
find_library(
        log-lib
        log)

# 设置链接, native-lib为总库,位置在 apk/lib/arm64-v8a/libnative-lib.so,如下方截图
# 通过${log-lib}把log库链接到总库中,总库的cpp代码,就可以使用android/log.h的库实现代码了
target_link_libraries(
        native-lib
        ${log-lib})

Android CMake_第3张图片

# 也可以写成这样
target_link_libraries(
        native-lib
        log)

这里是log库,是否还有其它库能写,保证写正确呢?

1) 先看下ndk版本,在local.properties文件中
ndk.dir=C\:\\Users\\xxxxxx\\Android\\Sdk\\ndk\\20.0.5594570

2) 看 app/build.gradle 中的 minSdkVersion设置的多少
minSdkVersion 21

3) 根据上方的内容去查找这文件即可
C:\Users\xxxxxx\Android\Sdk\ndk\20.0.5594570\build\cmake\system_libs.cmake
文件内容为:
set(NDK_SYSTEM_LIBS "libEGL.so;libGLESv1_CM.so;libGLESv2.so;libGLESv3.so;libOpenMAXAL.so;libOpenSLES.so;libaaudio.so;libamidi.so;libandroid.so;libbinder_ndk.so;libc.so;libcamera2ndk.so;libdl.so;libjnigraphics.so;liblog.so;libm.so;libmediandk.so;libnativewindow.so;libneuralnetworks.so;libstdc++.so;libsync.so;libvulkan.so;libz.so")

信息输出 - message

    (无) = 重要消息;
    STATUS = 非重要消息;
    WARNING = CMake 警告, 会继续执行;
    AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
    SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
    FATAL_ERROR = CMake 错误, 终止所有处理过程;

message("hello1 ================================")
message(STATUS "hello2 =========================")
message(WARNING "hello3 =========================")

Android CMake_第4张图片
输出的信息在这里查看:(记得安装到手机上先)
    地址:\app.cxx\cmake\debug\arm64-v8a\cmake_server_log.txt
Android CMake_第5张图片
先refresh,再make一下,也能在最下方的build中看:
Android CMake_第6张图片

变量 set

# 声明变量
# 只有字符串,没有int
set(mNumber 666)
message(STATUS "mNumber = ${mNumber}")   # 打印结果: mNumber = 666

# 列表  都是string类型
set(mList1 1 2 3 66 100)    # 这两种方式等价的
set(mList2 "100;200;500")   # 这两种方式等价的
message(STATUS "mList1 = ${mList1}")   # 打印结果: mList1 = 1;2;3;66;100
message(STATUS "mList2 = ${mList2}")   # 打印结果: mList2 = 100;200;500

条件命令 if

CMake关于 if 的介绍:https://cmake.org/cmake/help/v3.10/command/if.html

# true(1,ON,YES,TRUE,Y,非0的值)
# false(0,OFF,NO,FALSE,N,IGNORE,NOTFOUND)
set(mFlagIsON ON)
set(mFlagIsOFF OFF)

if(${mFlagIsON})
    message("mFlagIsON为 1,ON,YES,TRUE,Y,非0的值!")
endif()

if(NOT ${mFlagIsOFF})
    message("mFlagIsOFF为 0,OFF,NO,FALSE,N,IGNORE,NOTFOUND!")
endif()
set(mNum 101)
if(${mNum} STREQUAL 100)
    message("mNum 为 100!")
elseif(${mNum} STREQUAL 101)
    message("mNum 为 101!")
else()
    message("mNum 不为 100、101!")
endif()

循环 while

set(mStr "hello")
while(mStr STREQUAL "hello")
    message("mStr 为 hello!")
    set(mStr "${mStr}world")
    message("mStr 被修改为 ${mStr}")
endwhile()
set(mStr2 "helloworld")
while(NOT mStr2 STREQUAL "hello")
    message("mStr2 不为 hello!")
    break()
#    continue()
endwhile()

循环 foreach

CMake关于 foreach 的介绍:https://cmake.org/cmake/help/v3.10/command/foreach.html?highlight=foreach

foreach(item 1 2 3 66 100)
    message("foreach1 item=${item}")
endforeach()

打印结果:遍历每一个
foreach(item RANGE 10)
    message("foreach2 item=${item}")
endforeach()

打印结果: 从 1 到 10
# foreach(loop_var RANGE start stop [step])

foreach(item RANGE 1 20 2)
    message("foreach3 item=${item}")
endforeach()

打印结果: 从 1 开始,每次下标加2
set(mList1 1 2 3 66 100)

foreach(item IN LISTS mList1)
    message("foreach4 item=${item}")
endforeach()

打印结果:遍历每一个

函数 function

CMake关于 function 的介绍:https://cmake.org/cmake/help/v3.10/command/function.html?highlight=function
ARGC:传入的参数个数
ARGV:所有的参数
ARGV0:第一个参数

function(myFunction n1 n2 n3)
    message("n1= ${n1}")
    message("n2= ${n2}")
    message("n3= ${n3}")

    message("argc= ${ARGC}")

    message("argv= ${ARGV}")
    message("argv0= ${ARGV0}, argv1= ${ARGV1}, argv2= ${ARGV2}")
endfunction()

myFunction(100 299 99999)

打印结果:
n1= 100
n2= 299
n3= 99999
argc= 3
argv= 100;299;99999
argv0= 100, argv1= 299, argv2= 99999

静态库和动态库的区别

静态库

在程序编译时会被链接到目标代码中,相当于静态库中的代码被拷贝到总库中;
程序运行期将不再需要该静态库。

动态库

在程序编译时并不会被链接到目标代码中,只是做地址记录;
在程序运行期,通过地址记录,做地址会填;
因此程序运行期还需要动态库存在。

CMakeLists.txt 路径配置

默认是在:\app\src\main\cpp\CMakeLists.txt

也可以设置在其他位置,但名称必须是CMakeLists.txt

创建一个新的CMakeLists.txt

拷贝一份cpp下的CMakeLists.txt,到main目录下
Android CMake_第7张图片

修改app/build.gradle文件指定新的CMakeLists.txt

Android CMake_第8张图片

导入头文件 及 动态库

方式1

CMAKE_SOURCE_DIR 等于 CMakeLists.txt所在的地址目录
CMAKE_ANDROID_ARCH_ABI 等于 当前手机的CPU架构

## 导入fmod头文件
include_directories("fmodinc")

## 导入库文件
# CMAKE_SOURCE_DIR 等于 CMakeLists.txt所在的地址目录
# CMAKE_ANDROID_ARCH_ABI  等于 当前手机的CPU架构
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")

# 链接到总库中
# native-lib 总库
target_link_libraries(
        native-lib
        log
        fmod
        fmodL
)

Android CMake_第9张图片

方式2

## 导入fmod头文件
include_directories("fmodinc")

## 导入库文件
add_library(fmod SHARED IMMPORTED)
set_target_properties(fmod PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libfmod.so)

add_library(fmodL SHARED IMPORTED)
set_target_properties(fmodL PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}/libfmodL.so)

# 链接到总库中
target_link_libraries(
        native-lib
        log
        fmod
        fmodL
)

Android CMake_第10张图片

导入静态库

add_library(getndk STATIC IMPORTED)
set_target_properties(getndk PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libgetndk.a)

target_link_libraries(
        native-lib
        log
        getndk
)

Android CMake_第11张图片

源码构建方式

Android CMake_第12张图片

libcount:

Android CMake_第13张图片

libget:

Android CMake_第14张图片

app\src\main\cpp\CMakeLists.txt

cmake_minimum_required(VERSION 3.4.1)

file(GLOB SOURCE *.cpp *.c)
add_library(
        native-lib
        SHARED
        ${
     SOURCE})

add_subdirectory(${
     CMAKE_SOURCE_DIR}/libget)
add_subdirectory(${
     CMAKE_SOURCE_DIR}/libcount)

target_link_libraries(
        native-lib
        log
        get
        count
)

app\src\main\cpp\native-lib.cpp

#include 
#include 
#include 

#define TAG "AAAAAAAAAAAAAAAA"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG,  __VA_ARGS__);

extern "C" {
     
    #include "libget/getutil.h"
}

#include "libcount/countutil.h"

extern "C" JNIEXPORT jstring JNICALL Java_com_example_mycmaketest_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
     

    // get信息的输出显示
    LOGD("get1_action: %s", get1_action());
    LOGD("get2_action: %s", get2_action());

    // count信息的输出显示
    LOGD("add_action: %d", add_action(10, 20));
    LOGD("sub_action: %d", sub_action(100, 10));

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

参考文档

    developers 配置 CMake:https://developer.android.com/studio/projects/configure-cmake
    Android NDK导入C库示例(fmod): https://blog.csdn.net/yan13507001470/article/details/120559455

你可能感兴趣的:(AndroidNDK,Android,android,cmake)