cmake使用教程(六)-蛋疼的语法,5G音视频时代还不学NDK开发吗

62 阅读8分钟
1. Directory

当CMake处理一个项目时,入口点是一个名为CMakeLists.txt的源文件,这个一定是根目录下的CMakeLists.txt。这个文件包含整个工程的构建规范,当我们有多个子文件夹需要编译时,使用add_subdirectory(<dir_name>)命令来为构建添加子目录。添加的每个子目录也必须包含一个CMakeLists.txt文件作为该子目录的入口点。每个子目录的CMakeLists.txt文件被处理时,CMake在构建树中生成相应的目录作为默认的工作和输出目录。记住这一点非常关键,这样我们就可以使用外部构建了,而不必每次都使用蛋疼的内部构建,然后删除一堆文件才能从新构建。

2. Script

一个单独的<script>.cmake源文件可以使用cmake命令行工具cmake -P <script>.cmake选项来执行脚本。脚本模式只是在给定的文件中运行命令,并且不生成构建系统。它不允许CMake命令定义或执行构建目标。

3. Module

在Directory或Script中,CMake代码可以使用include()命令来加载.cmake。cmake内置了许多模块用来帮助我们构建工程,前边文章中提到的CheckFunctionExists。也可以提供自己的模块,并在CMAKE_MODULE_PATH变量中指定它们的位置。

cmake基本编写格式

先看一下定义的方式

名称表达式我认为的例子
space<match '[ \t]+'>任意个空格或者taba b
newline<match '\n'>换行符a\nb
line_comment'#' <any text not starting in a bracket_argument and not containing a newline>以'#"开头,不在'[]'块中,不包含换行符#bus
separationspace|newline空格或者换行a b=a\nb
lineendinglinecomment?newline从注释开头到换行符都不执行
command_invocationspace* identifier space* '(' arguments ')'
quoted_argument"quoted_element* "用引号包裹的参数"a"

文档看起来很蛋疼,我直接写一个最简单的

add_executable(hello world.c foo.c) #这是一个注释

也等于

add_executable(hello world.c foo.c) #这是一个注释

就是这么easy。注意参数这一块,可以用引号包裹起来,这代表一个参数,假如一行不能写完,则用\\符号来表示连接成一行,也可以不用引号,但是假如参数带有分隔符,则会被认为是多个参数。

定义变量

定义变量常用的函数是set(KEY VALUE),取消定义变量是unset(KEY)。 它们的值始终是string类型的,有些命令可能将字符串解释为其他类型的值。变量名是区分大小写的,可能包含任何文本,但是我们建议只使用字母数字字符加上_和-这样的名称。

变量的作用域和java基本一致,不多做讲解。

变量引用的形式为${variable_name},并在引用的参数或未引用的参数中进行判断。变量引用被变量的值替换,或者如果变量没有设置,则由空字符串替换。变量引用可以嵌套,并从内部进行替换,例如${outer_${inner_variable}veriable}。 环境变量引用的形式为$ENV{VAR},并在相同的上下文中作为正常变量引用。

cmake构建系统

这算是进入正文了。扯淡的介绍就不多讲了,直接干货。

可执行文件和库是使用add_executable()和add_library()命令定义的。生成的二进制文件有合适的前缀、后缀和针对平台的扩展。二进制目标之间的依赖关系使用target_link_libraries()命令表示。

add_library(archive archive.cpp zip.cpp lzma.cpp) add_executable(zipapp zipapp.cpp) target_link_libraries(zipapp archive)

在构建c程序的时候,因为要生成可执行文件,add_executable是必须的;构建安卓动态库的时候,add_library是必须的,因为jni需要调用动态库。

外部构建

前边提到过cmake的构建命令cmake .,也就是在当前目录构建工程,这样会生成一系列的缓存文件在当前目录,假如我们需要重新构建需要删除这些文件,其中CMakeCache.txt是必须删除的,否则不会构建最新的程序。 看一下我们在工程根目录下执行cmake后是什么情况:

 ~/Desktop/Tutorial/Step1/ tree -L 1 . ├── CMakeCache.txt ├── CMakeFiles ├── CMakeLists.txt ├── Makefile ├── Tutorial ├── TutorialConfig.h ├── TutorialConfig.h.in ├── cmake_install.cmake └── tutorial.cxx

生成的文件与源文件交叉在一起,相当混乱。我们可以采用外部构建来分隔源文件与生成的文件,当我们需要清空缓存重新构建项目时,就可以删除这个文件夹下的所有内容,重新运行构建命令,保持源文件的整洁,从而更容易管理项目。

首先新建一个文件夹build。这个文件夹就是我们用来存放生成的文件的目录,然后进入该目录,执行构建命令。

mkdir build # 创建build目录 cd build # 进入build目录 cmake .. # 因为程序入口构建文件在项目根目录下,采用相对路径上级目录来使用根目录下的构建文件

此时可以看到生成的文件全部在build文件夹下了,构建完全没问题。

 ~/Desktop/Tutorial/Step1/ tree -L 2 . ├── CMakeLists.txt ├── TutorialConfig.h.in ├── build │   ├── CMakeCache.txt │   ├── CMakeFiles │   ├── Makefile │   ├── TutorialConfig.h │   └── cmake_install.cmake └── tutorial.cxx

以后的项目讲解中将全部使用外部构建。

下面是我专门为讲解一些基本指令编写的代码

cmake_minimum_required (VERSION 2.6) project (Tutorial) message(STATUS PROJECTNAME)message(STATUS{PROJECT_NAME}) message(STATUS {PROJECT_SOURCE_DIR}) message(STATUS PROJECTBINARYDIR)message(STATUS{PROJECT_BINARY_DIR}) message(STATUS {Tutorial_SOURCE_DIR}) message(STATUS ${Tutorial_BINARY_DIR})

The version number.

set (Tutorial_VERSION_MAJOR 1) set (Tutorial_VERSION_MINOR 0)

configure a header file to pass some of the CMake settings

to the source code

configure_file ( "PROJECTSOURCEDIR/TutorialConfig.h.in""{PROJECT_SOURCE_DIR}/TutorialConfig.h.in" "{PROJECT_BINARY_DIR}/TutorialConfig.h" )

add the binary tree to the search path for include files

so that we will find TutorialConfig.h

include_directories("${PROJECT_BINARY_DIR}")

add the executable

add_executable(Tutorial tutorial.cxx)

  • 首先看message用法 message类似于一个向控制台输出日志的工具,但是功能又稍微强大一些,在一些模式下能够终止程序构建。

message([] "message to display" ...)

mode有以下几个模式

模式作用
(none)Important information
STATUSIncidental information
WARNINGCMake Warning, continue processing
AUTHOR_WARNINGCMake Warning (dev), continue processing
SEND_ERRORCMake Error, continue processing,but skip generation
FATAL_ERRORCMake Error, stop processing and generation
DEPRECATIONCMake Deprecation Error or Warning if variable CMAKE_ERROR_DEPRECATED or CMAKE_WARN_DEPRECATED is enabled, respectively, else no message.

STATUS我们经常用到。

  • 来看第一行:

cmake_minimum_required (VERSION 2.6)

为一个项目设置cmake的最低要求版本,并更新策略设置以匹配给定的版本(策略设置我永远也不会讲了)。无论是构建项目还是构建库,都需要这个命令。 它的语法是这样的

cmake_minimum_required(VERSION major.minor[.patch[.tweak]] [FATAL_ERROR])

版本号必须指定主次代号,后边的可选,请忽略可选项[FATAL_ERROR],完全没用。

假如你指定的版本号大于你安装的cmake版本,将会停止构建并抛出一个错误:

CMake Error at CMakeLists.txt:1 (cmake_minimum_required): CMake 3.11 or higher is required. You are running version 3.10.2

-- Configuring incomplete, errors occurred!

cmake_minimum_required必须在项目根目录下的最开始调用,也就是project()之前。在function()中调用该指令也可以,作用域将局限在函数内,但是必须以不影响全局使用为前提

  • 来看第二行

project (Tutorial)

指定项目的名称为Tutorial,构建项目必须使用这个命令,构建库可以不指定。文档如下:

project( [LANGUAGES] [...]) project( [VERSION [.[.[.]]]] [DESCRIPTION ] [LANGUAGES ...])

设置项目名称并将该名称存储在PROJECT_NAME变量中。同时也指定了四个变量:

PROJECT_SOURCE_DIR, _SOURCE_DIR PROJECT_BINARY_DIR, _BINARY_DIR

但是我们一般只使用前一个,这样更容易更改。在上边的代码中我们用message输出了这些变量的信息,执行构建命令后日志输出:

-- Tutorial -- /Users/saka/Desktop/Tutorial/Step1 -- /Users/saka/Desktop/Tutorial/Step1/build -- /Users/saka/Desktop/Tutorial/Step1 -- /Users/saka/Desktop/Tutorial/Step1/build

可以看到这几个变量确实输出了正确的值。

我们也可以在指定项目名称时直接指定版本号,假如没有指定,则版本号为空。 版本号存储在下边几个变量中:

PROJECT_VERSION, _VERSION PROJECT_VERSION_MAJOR, _VERSION_MAJOR PROJECT_VERSION_MINOR, _VERSION_MINOR PROJECT_VERSION_PATCH, _VERSION_PATCH PROJECT_VERSION_TWEAK, _VERSION_TWEAK

通常我们推荐使用前一个。现在测试一下,在CMakeLists.txt文件中修改代码:

最后

简历首选内推方式,速度快,效率高啊!然后可以在拉钩,boss,脉脉,大街上看看。简历上写道熟悉什么技术就一定要去熟悉它,不然被问到不会很尴尬!做过什么项目,即使项目体量不大,但也一定要熟悉实现原理!不是你负责的部分,也可以看看同事是怎么实现的,换你来做你会怎么做?做过什么,会什么是广度问题,取决于项目内容。但做过什么,达到怎样一个境界,这是深度问题,和个人学习能力和解决问题的态度有关了。大公司看深度,小公司看广度。大公司面试你会的,小公司面试他们用到的你会不会,也就是岗位匹配度。

选定你想去的几家公司后,先去一些小的公司练练,学习下面试技巧,总结下,也算是熟悉下面试氛围,平时和同事或者产品PK时可以讲得头头是道,思路清晰至极,到了现场真的不一样,怎么描述你所做的一切,这绝对是个学术性问题!

面试过程一定要有礼貌!即使你觉得面试官不尊重你,经常打断你的讲解,或者你觉得他不如你,问的问题缺乏专业水平,你也一定要尊重他,谁叫现在是他选择你,等你拿到offer后就是你选择他了。

金九银十面试季,跳槽季,整理面试题已经成了我多年的习惯!在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

本文在开源项目:【GitHub 】中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…