51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Android CMake使用方法介绍

CMake简介 {#CMake简介}

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

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

最低支持的版本 cmake_minimum_required {#最低支持的版本-cmake-minimum-required}

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

添加库 add_library {#添加库-add-library}

|---------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # 默认生成的,导入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}) |

查找库 find_library / target_link_libraries {#查找库-find-library-x2F-target-link-libraries}

|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | # 查找动态库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}) |

|-----------------|----------------------------------------------------------| | 1 2 3 4 | # 也可以写成这样 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 {#信息输出-message}

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

|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 | message("hello1 ================================") message(STATUS "hello2 =========================") message(WARNING "hello3 =========================") |

输出的信息在这里查看:(记得安装到手机上先)
地址:\app.cxx\cmake\debug\arm64-v8a\cmake_server_log.txt

先refresh,再make一下,也能在最下方的build中看:

变量 set {#变量-set}

|------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | # 声明变量 # 只有字符串,没有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 {#条件命令-if}

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

|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 {#循环-while}

|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 {#循环-foreach}

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

|-------------------|---------------------------------------------------------------------------------------------| | 1 2 3 4 5 | foreach(item 1 2 3 66 100) message("foreach1 item=${item}") endforeach() 打印结果:遍历每一个 |

|-------------------|---------------------------------------------------------------------------------------------| | 1 2 3 4 5 | foreach(item RANGE 10) message("foreach2 item=${item}") endforeach() 打印结果: 从 1 到 10 |

|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | # foreach(loop_var RANGE start stop [step]) foreach(item RANGE 1 20 2) message("foreach3 item=${item}") endforeach() 打印结果: 从 1 开始,每次下标加2 |

|-----------------------|-------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 | set(mList1 1 2 3 66 100) foreach(item IN LISTS mList1) message("foreach4 item=${item}") endforeach() 打印结果:遍历每一个 |

函数 function {#函数-function}

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

|------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 路径配置 {#CMakeLists-txt-路径配置}

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

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

创建一个新的CMakeLists.txt {#创建一个新的CMakeLists-txt}

拷贝一份cpp下的CMakeLists.txt,到main目录下

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

导入头文件 及 动态库 {#导入头文件-及-动态库}

方式1 {#方式1}

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

|------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ## 导入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 ) |

方式2 {#方式2}

|---------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ## 导入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 ) |

导入静态库 {#导入静态库}

|-------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 | add_library(getndk STATIC IMPORTED) set_target_properties(getndk PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libgetndk.a) target_link_libraries( native-lib log getndk ) |

源码构建方式 {#源码构建方式}

libcount:

libget:

app\src\main\cpp\CMakeLists.txt

|---------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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

|------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #include <jni.h> #include <string> #include <android/log.h> #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
参考链接:https://blog.csdn.net/yan13507001470/article/details/120807408


赞(1)
未经允许不得转载:工具盒子 » Android CMake使用方法介绍