CMake基本配置与注意事项

CMake

​ 在android studio 2.2及以上,构建原生库的默认工具是 CMake。

​ CMake是一个跨平台的构建工具,可以用简单的语句来描述所有平台的安装(编译过程)。能够输出各种各样的makefile或者project文件。Cmake 并不直接建构出最终的软件,而是产生其他工具的脚本(如Makefile ),然后再依这个工具的构建方式使用。

​ CMake是一个比make更高级的编译配置工具,它可以根据不同平台、不同的编译器,生成相应的Makefile或者vcproj项目。从而达到跨平台的目的。Android Studio利用CMake生成的是ninja,ninja是一个小型的关注速度的构建系统。我们不需要关心ninja的脚本,知道怎么配置cmake就可以了。从而可以看出cmake其实是一个跨平台的支持产出各种不同的构建脚本的一个工具。

CMake的脚本名默认是CMakeLists.txt

#cmake最低版本
cmake_minimum_required(VERSION 3.6.0) #指定项目
project(Main) #生成可执行文件 main
add_executable(main main.c) #执行cmake . 生成makefile
#再执行make即可生成main程序

message打印日志

可以使用message("打印日志")来打印日志

# log 信息输出的查看
# 以前的Cmake版本都是在output.txt, 现在最新版本Cmake在metadata_generation_stderr.txt或cmake_server_log,
# 路径`./app/.cxx/cmake/debug/armeabi-v7a/cmake_server_log.txt`
# 想及时更新你的日志,请安装一次即可 or Linked_C++_Projects
# 在Build也可以查看,注意:是点击Sync Now 才会看到 #[[
(无) = 重要消息;
STATUS = 非重要消息;
WARNING = CMake 警告, 会继续执行;
AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
FATAL_ERROR = CMake 错误, 终止所有处理过程;
]] message(STATUS "1SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "2SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "3SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "4SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "5SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "6SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "7SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "8SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "9SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message(STATUS "0SuccessD>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
message("10 OldCmakeVersion:output.txt, NewCmakeVersion:cmake_server_log.txt")

find_library查找一个NDK工具中的库

在创建一个新的C++项目工程后,在CMakeLists.txt中都会有find_library(log-lib log )这个函数,表示的是查找一个NDK工具中的log的动态库。

思考:我如何知道哪些库是可以写的,你怎么知道些一个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

问题1:你怎么知道是在 21.4.7075529?,问题2:为啥是arm-linux-androideabi?,问题3;为啥是16?

答:?1 (因为local.properties指定了NDK版本,或者是你当前的NDK版本)

答:?2 (因为我的手机是arm32的,而且在项目的build.gradle中配置了"armeabi-v7a" 所以是arm-linux-androideabi)

答:?3 (因为项目中的minSdkVersion是16)

添加多个源文件

如果源文件很多,那么一个个写进去是一件很麻烦的事情,这里有两种方法:

  1. file(GLOB source src/main/cmake/*.c src/main/cmake/*.cpp) # GLOB是固定的写法,source是一个变量名,表示src/main/cmake/下面的所有.c和.cpp文件添加到source里面来
  2. aux_source_directory(. DIR_SRCS)# 查找当前目录所有源文件 并将名称保存到 DIR_SRCS 变量,不能查找子目录
cmake_minimum_required(VERSION 3.6.0)
project(Main)
#查找当前目录所有源文件 并将名称保存到 DIR_SRCS 变量
#不能查找子目录
aux_source_directory(. DIR_SRCS)
message(${DIR_SRCS}) #也可以
file(GLOB DIR_SRCS *.c) add_executable(main ${DIR_SRCS})

CMake中引用其他的 CMake

如果在cmake中需要使用其他目录的cmakelist

cmake_minimum_required (VERSION 3.6.0)
project (Main)
aux_source_directory(. DIR_SRCS)
# 添加 child 子目录下的cmakelist
add_subdirectory(child)
# 指定生成目标
add_executable(main ${DIR_SRCS})
# 添加链接库
target_link_libraries(main child)
#===========================================================================================
#child目录下的cmake就是:
cmake_minimum_required (VERSION 3.6.0)
aux_source_directory(. DIR_LIB_SRCS)
# 生成链接库 默认生成静态库
add_library (child ${DIR_LIB_SRCS})
#指定编译为静态库
add_library (child STATIC ${DIR_LIB_SRCS})
#指定编译为动态库
add_library (child SHARED ${DIR_LIB_SRCS})

在上面的例子中都是生成可执行文件,让我们对cmakelist有了一定的了解。现在到android studio中使用cmakelist

#NDK中已经有一部分预构建库 ndk库已经是被配置为cmake搜索路径的一部分 所以可以
findLibrary(log-lib log)
target_link_libraries( native-lib
${log-lib} )
#设置cflag和cxxflag
#定义预编译宏:TEST,-D就是定义预编译宏的意思
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DTEST" )
set(CMAKE_Cxx_FLAGS "${CMAKE_Cxx_FLAGS} -DTEST" )
#其实直接这样就行
target_link_libraries( native-lib
log )

添加其他预编译库

添加其他预编译库(已经提前编译好的库)

#使用 IMPORTED 标志告知 CMake 只希望将库导入到项目中
#如果是静态库则将shared改为static
add_library( imported-lib
SHARED
IMPORTED )
# 参数分别为:库、属性、导入地址、so所在地址
set_target_properties(
imported-lib
PROPERTIES
IMPORTED_LOCATION
${CMAKE_SOURCE_DIR}/src/${ANDROID_ABI}/libimported-lib.so )
#为了确保 CMake 可以在编译时定位头文件
#这样就可以使用 #include <xx> 引入
#否则需要使用 #include "path/xx"
include_directories( imported-lib/include/ ) #native-lib 是自己编写的源码最终要编译出的so库
target_link_libraries(native-lib imported-lib)
#===========================================================================================
# 添加其他预编译库还可以使用这种方式
# 使用-L指导编译时库文件的查找路径
# set方法相当于定义一个变量
# 变量名 CMAKE_C_FLAGS = ${CMAKE_C_FLAGS} + 自己设置的值(${CMAKE_C_FLAGS} (原来的CMAKE_C_FLAGS变量的值 + 自己定义的值)
# 如果有多个路径:set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" -LXXX -LXXX -LXXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Lxx")
# 为了确保 CMake 可以在编译时定位您的标头文件
include_directories( imported-lib/include/ ) # native-lib 是自己编写的源码最终要编译出的so库
target_link_libraries(native-lib imported-lib)

像这些CMAKE_SOURCE_DIR和ANDROID_ABI等都是CMake内部预设好了的,它们是在.../Android/sdk/cmake/3.6.4111459/android.toolchain.cmake这个文件,我们在执行CMakeLists.txt的时候,会去读取android.toolchain.cmake这个文件

常用指令:

#set命令表示声明一个变量source 变量的值是后面的可变参数
set(source a b c)
message(${source}) #逻辑判断 计较字符串
set(ANDROID_ABI "areambi-v7a")
if(${ANDROID_ABI} STREQUAL "areambi")
message("armv5")
elseif(${ANDROID_ABI} STREQUAL "areambi-v7a")
message("armv7a")
else() endif()
//还可以在gradle中使用 arguments  设置一些配置
externalNativeBuild {
cmake {
arguments "-DANDROID_TOOLCHAIN=clang", //使用的编译器clang/gcc
"-DANDROID_STL=gnustl_static" //cmake默认就是 gnustl_static
cFlags "" //这里也可以指定cflag和cxxflag,效果和之前的cmakelist里使用一样
cppFlags ""
}
}

5.0及以下与6.0及以上的注意事项:

​ 存在两个动态库 libhello-jni.so 与 libTest.so。

libhello-jni.so依赖于libTest.so (使用NDK下的ndk-depends可查看依赖关系),则:

//<=5.0:
System.loadLibrary("Test");
System.loadLibrary("hello-jni");
//>=6.0:
System.loadLibrary("hello-jni");
  • 在4.4上 如果load一个动态库 ,需要先将这个动态库的依赖的其他动态库load进来
  • 在6.0以下 System.loadLibrary 不会自动为我们加载依赖的动态库
  • 在6.0以上 System.loadLibrary 会自动为我们加载依赖的动态库

Android.mk

​ 使用Android.mk在 >=6.0 设备上不能再使用预编译动态库(静态库没问题):

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)
LOCAL_MODULE := Test
#libTest.so放在当前文件同目录
LOCAL_SRC_FILES := libTest.so
#预编译库
include $(PREBUILT_SHARED_LIBRARY) include $(CLEAR_VARS)
#引入上面的Test模块
LOCAL_SHARED_LIBRARIES := Test
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)

上面这段配置生成的libhllo-jni在>=6.0设备中无法执行。目前还没有找到在>=6.0设备的解决方法,最好是使用CMake

CMake

​ 使用CMakeList.txt在 >=6.0 设备上引入预编译动态库:

cmake_minimum_required(VERSION 3.4.1)

file(GLOB SOURCE *.c )
add_library(
hello-jni
SHARED
${SOURCE} ) #这段配置在6.0依然没问题
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L[SO所在目录]") #这段配置只能在6.0以下使用 原因和android.mk一样
#add_library(Test SHARED IMPORTED)
#set_target_properties(Test PROPERTIES IMPORTED_LOCATION [SO绝对地址]) target_link_libraries( hello-jni Test )

Android NDK 开发:CMake 使用

CMake 入门实战

CMake 使用教程

CMake使用简介及CMakeList.txt编写

CMake基本配置与注意事项的更多相关文章

  1. CMake交叉编译配置

    很多时候,我们在开发的时候是面对嵌入式平台,因此由于资源的限制需要用到相关的交叉编译.即在你host宿主机上要生成target目标机的程序.里面牵扯到相关头文件的切换和编译器的选择以及环境变量的改变等 ...

  2. [转]@Transactional spring 配置事务 注意事项

    @Transactional spring 配置事务 注意事项 [@more@] @Transactional spring 配置事务 注意事项 1. 在需要事务管理的地方加@Transactiona ...

  3. cmake 查看配置选项

    cmake 查看配置选项可以用如下命令 cmake . -LH 查看help > cmake -h    cmake version 2.6-patch 4 Usage cmake [optio ...

  4. Android Studio 2.2以上支持了Cmake的配置JNI的相关参数

    Android Studio 2.2以上支持了Cmake的配置JNI的相关参数,简化了通过Android.mk配置.并很好的继承了C++的编辑方式.以下是对应的引入第三方so和第三方.cpp文件的路径 ...

  5. Spring Cloud Eureka集群配置及注意事项(Greenwich版本)

    Spring Cloud Eureka集群配置及注意事项(Greenwich版本) 一·概述 Spring Cloud Netflix Eureka 是一个提供服务注册与发现的套件.服务提供者只需要将 ...

  6. MANIFEST.MF详解及配置的注意事项

    一.详解 打开Java的JAR文件我们经常可以看到文件中包含着一个META-INF目录, 这个目录下会有一些文件,其中必有一个MANIFEST.MF,这个文件描述了该Jar文件的很多信息,下面将详细介 ...

  7. 不同OpenCV版本和不同VS版本之间进行配置的注意事项

    下面内容为不同系统和不同版本VS+不同版本OpenCV之间进行配置时的注意事项.本教程中开始提到如果VS版本和OpenCV版本相匹配的话,只要按上述步骤配置都是没有问题的.但是如果说版本不匹配的话,就 ...

  8. Apache,PHP,MySQL,PMA手动配置的注意事项

    注:本文之前发布在自己的QQ空间,复制过来的时候,颜色信息丢失了,回头有空再把颜色重新标上! 前言:LAMP(Linux+Apache+MySQL+PHP)环境是目前开源社区最活跃的开发和运行平台,有 ...

  9. Win10 下Cmake编译配置 Opencv3.1 + Cuda7.5 + VS2013

    折腾了三天终于配置成功了,在此写下编译配置的全部步骤和遇到的很多坑. 整体介绍: OpenCV 中 CUDA 实现的函数还不是太多,使用前要在OpenCV的官网上确认以下你想要的功能是否已经实现,否则 ...

  10. cmake安装配置及入门指南

    前言 今天,从github下载代码学习,让我用cmake编译,纳尼?make我知道,cmake是啥鬼?天啊,无知很可怕!赶紧mark一波,虽然很耽误学习进度,但感觉还是要get一波! 一.安装准备 感 ...

随机推荐

  1. 2022 JuiceFS 社区用户调研结果出炉

    为了使 JuiceFS 的发展更贴合用户的真实需求,我们在三周前向社区发出了一份调研问卷.此次调研面向已经将 JuiceFS 应用于生产环境的用户,了解其在应用 JuiceFS 前和使用中的体验与评价 ...

  2. 图(树)的深度优先遍历dfs

    图的深度优先遍历 深度优先,即对于一个图或者树来说,在遍历时优先考虑图或者树的单一路径的深度.示意图如下 即深度优先搜索的核心就是对一个路径一直向下搜索,当搜索到头时就回溯到前一状态再寻找别的路 深搜 ...

  3. Java 递归的方式将list集合的某一字段拼接单个String

    场景介绍 要将list 集合中的某一个字段合并成一个字符串,并且要用符号 "|" 分割开每个拼接后的字段. 一个例子胜于一切的文字表达,拼接后的结果如下 str1|str2|str ...

  4. Rancher 2.x 安装

    Rancher 是一个容器管理平台.Rancher 简化了使用 Kubernetes 的流程. 下面记录一下手动安装Rancher的步骤 1.  部署 Rancher Server 执行以下命令即可( ...

  5. DS18B20数字温度计 (二) 测温, ROM和CRC算法

    目录 DS18B20数字温度计 (一) 电气特性, 寄生供电模式和远距离接线 DS18B20数字温度计 (二) 测温, ROM和CRC算法 DS18B20数字温度计 (三) 1-WIRE总线 ROM搜 ...

  6. OpenStack调度器

    计算使用 nova-scheduler 服务来确定如何调度计算请求 默认配置中,调度程序会考虑以下所有条件的主机: 位于请求的可用区 (map_az_to_placement_aggregate) 放 ...

  7. Linux下SQLPLUS替代工具rlwrap安装使用

    rlwrap工具可以解决linux下sqlplus 提供浏览历史命令行的功能,和删除先前输入错误的字母等问题 1.安装 需要readline包 这个安装光盘就有 [root@asm RedHat]# ...

  8. Java并发编程实例--16.使用ReentrantLock实现线程同步

    Java提供另一机制去同步代码块.它比synchronized关键字更强大且易用. 它是基于Lock接口和其实现类例如:ReentrantLock. 这一机制对比synchronized关键字的优势在 ...

  9. heapq.merge()高效合并有序序列

    import heapq import random # 针对较大的数据集,采用heapq中的merge()方法 # merge()不是对整个合并后的序列排序,而是使用一个堆一次一个元素的生成一个新序 ...

  10. chrony同步时间

    chrony文件组成 包:chrony 两个主要程序:chronyd和chronyc - chronyd:后台运行的守护进程,用于调整内核中运行的系统时钟和时钟服务同步.它确定计算机增减时间的比率,并 ...