CMake

栏目: C · 发布时间: 7年前

内容简介:CMake单行注释使用 # ,多行注释使用#[[]]CMake中所有变量都是string类型。可以使用set()和unset()命令来生命或者移除一个变量

CMake

什么是CMake

  • 在Android Studio2.2和以上版本,构建原生库的默认 工具 是CMake
  • CMake是一个跨平台的构建工具,可以使用简洁的语句来描述所有平台的安装(编译过程)。能够输出各种各样的makefile或者project文件。CMake并不直接构建出最终的软件,而是产生其他工具脚本比如makefile,然后在依据这个工具的构建方式使用。
  • CMake是一个比make更高级的编译配置工具,它可以根据不同的平台,不同的编译器,生成相应的makefile或者vcproj项目,从而达到跨平台的目的。Android Studio利用CMake生成的是ninja。ninja是一个小型的关注速度的构建系统。我们一般不需要关心ninja的脚本,只需要知道怎么配置CMake就行了
  • CMake是一个跨平台的支持产出各种不同的构建建脚本的一个工具。

CMake源文件

  • CMake源文件包含命令、注释、空格和换行
  • 已CMakeLists.txt命名或者以.cmake为扩展名
  • 可以通过add_subdirectory()命令吧子目录的CMake源文件添加进来
  • CMake源文件中所有有效的语句都是命令,可以是内置命令或者自定义的函数或宏命令。

CMake的注释

单行注释使用 # ,多行注释使用#[[]]

#单行注释
#[[
多行注释多行注释
]]

CMake变量

CMake中所有变量都是string类型。可以使用set()和unset()命令来生命或者移除一个变量

变量的引用使用${变量名}

变量名是大小写敏感的

想要看到message命令打印的信息,build工程然后在路径app\externalNativeBuild\cmake\debug\armeabi-v7a\cmake_build_output.txt.txt中就能看到

#声明变量
set(name 123)
#引用变量 message是打印命令
message("name = ${name}")

CMake列表

  • 列表也是字符串,可以把列表看成一个特殊的变量,它有多个值
  • 语法格式:set(列表名 值1 值2…)
  • 引用:${列表名}
    #声明列表
    set(list_var 1 2 3 4 5 )
    #或者
    set(list_1 "1;2;3;4;5")
    #打印
    message("list_var=${list_var}")
    

Cmake操作符

类型 名称
一元 EXIST,COMMAND,DEFINED
二元 EQUAL,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,STREQUAL,STRLESS,STRLESS_EQUAL,STRGREATER,STRGREATER_EQUAL,VERSION_EQUAL,VERSION_GREATER,VERSION_GREATER_EQUAL,MATCHES
逻辑 NOT,AND,OR

这些操作符都是大小写敏感的。优先级带括号的>一元>二元>逻辑

布尔常量值

类型
true 1,ON,YES,TRUE,Y,非0的值
false 0,OFF,FALSE,N,IGNORE,NOTFOUUND,空字符串,以-NOTFOUND结尾的字符串

条件命令

if(表达式) elseif

set(if_tap OFF)
set(elseif_tap ON)
if(${if_tap})
    message("if")
elseif(${elseif_tap})
    message

循环命令

while(表达式) endwhile(表达式) break()可以跳出整个循环。continue()可以跳出当前循环。

set(a "")
while(NOT a STREQUAL "XXX")
    set(a "${a}x")
    message("a = ${a}")
endwhile()

循环遍历

第一种:foreach(循环变量 参数1 参数2…)

endforeach(循环变量)。break()可以跳出整个循环。continue()可以跳出当前循环

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

第二种:foreach(循环变量 RANGE total) endforeach(循环变量)。循环范围从0到total

foreach(item RANGE 3)
    message("item = ${item}")
endforeach(item)

第三种:foreach(循环变量 RANGE start stop step) endforeach(循环变量)。循环变量从start到stop,每次增量为step

foreach(item RANGE 0 7 3)
    message("item = ${item}")
endforeach(item)
--------
打印为0 3 6

第四种:foreach(循环变量 IN LISTS 列表)

endforeach(循环变量)

set(list_var 1 2 3)
foreach(item IN LISTS list_var)
    message("item = ${item}")
endforeach(item)

自定义函数命令

自定义函数命令格式:function( [arg1[arg2[arg3]]]) endfunction( )

函数命令调用:name(实参列表)

function(func x y z)
    message("call function func")
    message("x = ${x}")
    message("y = ${y}")
    message("z = ${z}")
    message("ARGC = ${ARGC}")
    message("agr1 = ${ARGV0} arg2 = ${ARGV1} arg3 = ${ARGV2}")
endfunction(func)

func(1 2 3)

ARGC:表示传入产出的个数

ARGV: 表示所有参数列表

ARGV0: 第一个参数 ARGV1:第二个参数 ARGV2 第二个参数

自定义宏命令

自定义宏命令格式:macro( [arg1[arg2[arg3]]]) endfunction( )

宏命令用:name(实参列表)

计算机科学里的宏(Macro),是一种批量批处理的称谓。一般说来,宏是一种规则或模式,或称语法替换

macro(ma x y z)
    message("call macro ma")
    message("x = ${x}")
    message("y = ${y}")
    message("z = ${z}")
endmacro

ma(1 2 3)

CMake作用域

  • 全局层:cache变量 在整个项目范围可见,一般在set定义变量时,指定CACHE参数就能定义为cache变量
  • 目录层:在当前目录CMakeLists.txt中定义,以及在该文件包含的其他cmake源文件中定义的变量
  • 函数层:在命令哈数中定义的变量,属于函数作用域内的变量

CMakeLists.txt中命令解析

使用AndoridStudio创建一个C++工程后,系统会默认给我们创建一个CMakeLists.txt文件

#指定cmake最低支持的版本
cmake_minimum_required(VERSION 3.4.1)
#
add_library(
        native-lib

        SHARED

        native-lib.cpp)
find_library( 
        log-lib

        log)
target_link_libraries( 
        native-lib

        ${log-lib})

cmake_minimum_required(VERSION 3.4.1)是指定cmake最低支持的版本

aux_source_directory(. DIR_SRCS)第一个参数传入一个目录的路径, . 代表查找当前目录所有源文件,并将云文件名称列表保存到第二个参数DIR_SRC变量,不能查找子目录。

add_library添加一个库或者导入预编译的库

添加一个库:

  • 添加一个库文件,名称为
  • 指定STATIC,SHSRED,MODULE参数来指定库的类型,STATIC:静态库;SHARED:动态库;MODULE:在使用dyld的系统中有效,如果不支持dyld等同于SHARED
  • EXCLUDE_FORM_ALL:表示该库不会被默认构建
  • sorece1 sorece2….sourceN用来指定库的源文件
    add_library(<name> [STATIC|SHARED|MODULE]
    [EXCLUDE_FROM_ALL] source1 source2...sourceN)
    

导入预编译的库

  • 添加一个已存在的预编译的库名为
  • 一般配合set_target_properties使用
    add_library(<name> <SHARED|STATIC|MODULE|UNKNOWN> IMPORTED)
    #比如
    add_library(test SHARED IMPORTED)
    set_target_projecties(
        test#指明目标库的名称
        #指明要设置的参数库路径
        #/${ANDROID_ABI}/libtest.so#导入库的路径
        PROPRETIES IMPORTED_LOCATION)
    

set设置CMake变量

#设置可执行文件的输出路径(EXCUTABLE_OUTPUT_PATH是全局变量)
set(EXECUTABLE_OUT_PATH [out_path])

#设置库文件的输出路径(LIBRARY_OUT_PATH是全局变量)
set(LIBRARY_OUT_PATH [output_path])

#设置C++编译参数(CMAKE_CXX_FLAGS是全局变量)
set(CMAKE_CXX_FLAGS "-Wall std=c++ll")

#设置源文件集合(SOURCE_FILES是本地变量即自定义变量)
set(SOURCE_FILES main.cpp test.cpp...)

include_directories设置头文件目录,相当于g++选项中的-l参数

#可以用相对路径或者绝对路径,也可以使用自定义的变量值
include_directories(./include ${MY_INCLUDE})

add_executable添加可执行文件

#第一个参数文件名 第二个路径
add_executable(<name> #{SRC_LIST})

target_link_libraries将若干个文件链接到目标库文件,链接的顺序应该符合gcc链接顺序规则。

target_link_libraries(<name> lib1 lib2 lib3)

#如果出现互相依赖的静态库,CMake会允许依赖图中包含循环依赖比如:
add_library(A STATIC a.c)
add_library(B STATIC b.c)
target_link_libraries(A B)
target_link_libraries(B A)
add_executable(main main.c)
target_link_libraries(main A)

被链接的库放在依赖它的库的后面,即如果上面的命令中lib1依赖于lib2,lib2又依赖于lib3,则在前面的命令中,必须严格按照lib1 lib2 lib3的顺序排列否则会报错

add_definitions添加编译参数。为当前路径以及子目录文件假如有D引入的define falg

add_definitions(-DFOO -DDEBUG ...)

add_subdirectory如果当前目录下还有子目录时,可以使用add_subdirectory,子目录中也需要包含有CMakeLists.txt

#dub_dir:指定包含CMakeLists.txt和源码文件的子目录的位置
#binary_dir:是输出路径,一般可以不指定
add_definitions(sub_dir [binary_dir])

file文件操作命令

#将message写入filename文件中,会覆盖文件原有内容
file(WRITE filename "message")
#将message写入filename文件中,会追加在文件末尾
file(APPEND filename "message")
#从filename文件中读取内容并存储到var变量中,如果指定了numBytes和offset
#则从offset处开始最多度numBytes个字节
#另外如果指定了HEX参数,则内容会以十六进制形式存储在var变量中
file(READ filename var [LIMIT numBytes] [OFFSET offset] [HEX])
#重命名文件
file(RENME <oldname> <newname>)
#删除文件 等于rm命令
file(REMOVE [file1...])
#根据指定url下载文件
#timeout超市事件;下载状态会保存到status中;
#下载日志会被保存到log;
#sum指定多下载文件预期的MD5值
#如果指定hi自定进行比对,
#如果不一致则返回一个错误:SHOW_PROGRESS
#进度信息会以状态信息的形式被打印出来
file(DOWNLOAD url file [TIMEOUT timeout] [STATUS status] [LOG log] [EXPECTED_MD5 sum]
[SHOW_PROGRESS])
#创建目录
FILE(MAKE_DIRECTORY [dir1 dir2 ...])
#会把path转换为以unix的/开头的cmake风格路径保存在result总
file(TO_CMAKE_PATH pathresult)
#会把cmake风格的路径转换为本地路径风格window下用“\” unix下用“/”
file(TO_NATIVE_PATH path result)
#将会为所有匹配查询表达式的文件生成一个文件list
#并将该list存储进变量variable里面
#如果一个表达式指定了RELATIVE,返回的结果
#将会是相对于给定路径的相对路径
#查询表达式例子:*.cxx,*.vt?
#NOTE:按照官方文档说法,不建议使用file的GLOB指令来收集工程的源文件。
file(GLOB variable [RELATIVE path] [globbing expressions])

set_directory_properties()设置某个路径的一种属性

set_directory_properties(PROPERITIES prop1 value1 prop2 value2)

prop1 prop2,取值范围INCLUDE_DIRECTORIES,LINK_DIRECTORIES,INCLUDE_REGULAR_EXPRESSION,ADDITIONNAL_MAKE_CLEAN_FILES

set_property() :在给定的作用域内设置一个命名的属性

set_property(<GLOBAL | DIRECTORY [dir] |
TARGET [target...] |
SOURCE [src1...] |
TEST [test1...] |
CACHE [entry1 ...]>
[APPENT]
PROPERTY <name> [value...])

PROPERTY参数是必须的;第一个参数决定了属性可以影响的作用域:

  • GLOBAL:全局作用域
  • DIRECTORY:默认当前路径,也可以用[dir]指定路径
  • TARGET:目标作用域,可以是0个或多个已有目标
  • SOURCE:源文件作用域,可以是0个或多个源文件,源文件只对同目录有用
  • TEST:测试作用域,可以是0个或多个已有的测试
  • CACHE:必须指定0个或多个cache中已有的条目

如果源文件很多,把所有文件一个一个加入很麻烦,可以使用aux_source_directory命令或file命令,会查找指定目录下的所有源文件,然后将结果存进指定的变量名中。

#查找当前目录多有源文件 并将名称到存到DIR_SRCS
#中,不能查找子目录
aux_source_directory(. DIR_SRCS)

#也可以使用
#file(GLOB DIR_SRCS *.c  *.cpp)

add_library(native-lib
        SHARED
        ${DIR_SRCS})

多目录多源文件处理

  • 主目录中的CMakeList.txt中添加add_subdirectory(child)命令,指明本项目包含一个子项目child并在target_link_libraries指明本项目所需要链接一个名为chlid的库
  • 子目录child中创建CMakeLists.txt,这里child编译为共享库

主目录:

cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. DIR_SRCS)
#添加child子目录下的CMakeLists.txt
add_subdirectory(child)

add_library(
    native_lib
    SHARED
    ${DIR_SRCS}
)
target_link_libraries(native-lib child)

child目录:

cmake_minimum_required(VERSION 3.4.1)
aux_source_directory(. DIR_LIB_SRCS)
add_library(
    child
    SHARED
    ${DIR_SRCS}
)

添加预编译库

  • 假如项目中引入了libimported-lib.so
  • 添加add_library命令,第一个参数是模块名,第二个参数SHARED表示动态库,第三个参数IMPORTED表示以导入的形式添加
  • 添加set_targetOproperties命令设置导入路径属性到target_link_libraries命令参数中,表示native-lib需要连接imported-lib模块

Android 6.0之前

cmake_minimum_required(VERSION 3.4.1)
#使用IMPORTED标志告诉CMake 只希望将库导入到项目中
#如果静态库则将shared改为static
add_library( imported-lib
    SHARED
    IMPORTED)
#参数分别为库、属性、导入地址、库所在地址
set_target_properties(
    imported-lib
    PROPERTIES
    IMPORTED_LOCATION
    <路径>/libimported-lib.so
    )
aux_source_directory(. DIR_SRCS)
add_library(
    native-lib
    SHARED
    ${dir_SECS}
)
target_link_lbraries(native-lib imported)

Android 6.0之后

#set命令定义一个变量
#CMAK_C_FLAGS:c的参数会传递给编译器
#付过是c++文件,需要用CMAKE_CXX_FLAGS
#-L:库的查找路径
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L[SO所在目录]")

添加头文件的目录

为了确保CMake可以在编译时定位头文件,使用include_directories,相当于g++选项中的-l参数。这样就可以使用#include<xx.h>,否则需要使用#include”path/xx.h”

cmake_minimum_required(VERSION 3.4.1)
#设置头文件目录
include_directiories(<文件目录>)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -L[SO所在目录]")
aux_source_directory(. DIR_SRCS)
add_library(
    native-lib
    SHARED
    ${dir_SECS}
)
target_link_lbraries(native-lib imported)

build.gradle配置

android {
     defaultConfig {
           externalNativeBuild {
            cmake {
                //使用编译器clang/gcc
                //cmake默认就是gnustl_static
                arguments "-DANDROID_TOOLCHAIN=clang","-DANDROID_STL=gnustl_static"
                //指定cflags和cppflags,效果和cmakelist使用一样
                cppFlags ""
                cppFlags ""
                //指定需要编译的cpu架构
                abiFilters "armeabi-v7a"
            }
        }
     }
      externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.10.2"
        }
    }
}

练习

使用AndoridStudio新建一个C++项目,系统会为我们建好一个CmakeLists.txt文件

#指定cmake最小支持版本
cmake_minimum_required(VERSION 3.4.1)
#添加一个库,根据native-lib.cpp文件编译一个native-lib动态库
add_library( 
        native-lib
        SHARED
        native-lib.cpp)
#查找系统库,这里查找的是系统日志库
#默认会到 skd的ndk路径下面去找比如:sdk\ndk-bundle\platforms\android-28\arch-arm\usr\lib
find_library(
        log-lib
        log)
#设置依赖的库,第一个参数必须为依赖的模块,顺序不能改
target_link_libraries(
        native-lib
        ${log-lib})

如何集成第三方库比如现在继承fmod库到自己的项目(fmod是一个音频引擎,可以制作各种各样的魔幻声音)

  1. 首先去官网下载sdk https://www.fmod.com/download 它有各个平台的这里选择Android的

  2. 下载之后解压进入到api/core目录可以看到3个文件夹examples(例子),inc(头文件),lib(动态库)

  3. 先把头文件复制到我们工程的cpp目录下面

  4. 然后在cpp目录的同级新建jinLibs文件夹,把动态库都复制进去,lib文件夹中有个fmod.jar,这个jar包也放到我们工程的libs文件中引入,防止运行的时候找不到类。

等会使用模拟器测试,所以app.gradle中配置cpu的类型为x86

externalNativeBuild {
          cmake {
              abiFilters "x86"
          }
      }

      ndk {
          abiFilters 'x86'
      }
  1. 配置CMakeLists.txt文件

    #指定cmake最小支持版本
    cmake_minimum_required(VERSION 3.4.1)
    #设置头文件目录
    include_directories(${CMAKE_SOURCE_DIR}/inc)
    #添加一个库,根据native-lib.cpp文件编译一个native-lib动态库
    add_library( 
            native-lib
            SHARED
            native-lib.cpp)
    #设置第三方so库的路径
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")
    #查找系统库,这里查找的是系统日志库
    #默认会到 skd的ndk路径下面去找比如:sdk\ndk-bundle\platforms\android-28\arch-arm\usr\lib
    find_library(
            log-lib
            log)
    #设置依赖的库,第一个参数必须为依赖的模块,顺序不能改。fmod和fmodL是动态库的名字
    target_link_libraries(
            native-lib
            fmod
            fmodL
            ${log-lib})
    
  2. 到我们自己的cpp文件中编写代码

这里引入fmod的头文件,然后打印一下其版本号

#include <jni.h>
#include <string>
#include <fmod.hpp>
#include <android/log.h>

using namespace FMOD;

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

    System *system;
    System_Create(&system);
    unsigned version;
    system->getVersion(&version);
    __android_log_print(ANDROID_LOG_ERROR,"text","FMOD_VERSION:%08x",version);
    return env->NewStringUTF(hello.c_str());
}

运行项目可以在log中看到打印日志

2019-05-25 15:37:50.261 29585-29585/com.chs.cmake E/text: FMOD_VERSION:00020001

OK继承成功。


以上所述就是小编给大家介绍的《CMake》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Neural Networks for Applied Sciences and Engineering

Neural Networks for Applied Sciences and Engineering

Samarasinghe, Sandhya / CRC Pr I Llc / 2006-9 / $ 118.59

In response to the exponentially increasing need to analyze vast amounts of data, Neural Networks for Applied Sciences and Engineering: From Fundamentals to Complex Pattern Recognition provides scient......一起来看看 《Neural Networks for Applied Sciences and Engineering》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具