首先是编写好的CMakeLists.txt文件
cmake_minimum_required(VERSION 3.16)
project(opencv_test)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenCV REQUIRED)
add_executable(opencv_test main.cpp) #readvideo basic_operations encap_functions my_armor
target_link_libraries(opencv_test ${OpenCV_LIBS})
后面依次解释上面的代码
前置知识
编译过程
Martin’s blog
编译分为四个步骤:预编译 - 编译 - 汇编 - 链接
每一步会生成不同的文件:
下面分别解释四个过程:
预编译
预编译过程又分为四步:
展开头文件
这里需要补充的是,静态链接库会在编译时加入代码中,但是动态链接库如OpenCV中的库就不会加入代码中
我们平时#include<filename>
或者#include"filename"
包含的就是filename
中的代码,将filename
中的代码加入我们自己的代码中
宏替换
宏,也就是我们所说的#define
和typedef
,将我们定义的写法替换成标准的写法
去掉注释
这个不用多说哈
条件编译
作为个人来说,这个我基本上没有遇到过。
补充
还有的话就是添加行号和文件标示,这样的在调试和编译出错的时候才知道是是哪个文件的哪一行
但是具体指的就是#ifdef,#define,#endif
这些东西,对他们进行判断检查,防止有东西被重复引用
编译
编译过程就是将代码装换成汇编代码,这个过程也分为两步
保存函数地址符
编译器在每个文件中保存一个函数地址符表,该表中存储着当前文件内包含的各个函数的地址
编写汇编代码
因为这步要生成汇编代码,即一条一条的指令,而调用函数的代码会被编译成一条call
指令,call
指令后面跟的是jmp
指令的汇编代码地址,而jmp
指令后面跟的才是“被调用的函数编译成汇编代码后的第一条指令”的地址,但是给call
指令后面补充上地址的工作是在链接的时候做的事情
汇编
这个环节说起来很简单,就是将汇编代码转换成二进制代码(但是是怎么具体实现的还需要进一步学习)(我可以一直挖坑的)
也分为四步
1、词法分析
2、语法分析
3、语义分析
4、优化后生成相应的汇编代码
也就是从 高级语言->汇编语言->机器语言(二进制)
链接
还记得那张图片里面的汇编后的文件吗?我们要做的就是将汇编过程中生成的多个.o
文件链接到一起,生成一个可执行的.exe
文件
但是在这个过程中,编译器做的一个重要的事情是将每个文件中call
指令后面的地址补充上;方式是从当前文件的函数地址符表中开始找,如果没有,继续向别的文件的函数地址符表中找,找到后填补在call
指令后面,如果找不到,则链接失败
注释
call
jmp
前置知识结束,正式开始讲解CMakeLists.txt的编写
首先是各个命令的讲解
cmake_minimum_required
:其语法为
CMAKE_MINIMUM_REQUIRED(VERSION versionNumber [FATAL_ERROR])
比如 CMAKE_MINIMUM_REQUIRED(VERSION 2.5 FATAL_ERROR)
如果 cmake
版本小于 2.5
,则出现严重错误,整个过程中止
project
:
PROJECT(projectname [CXX] [C] [Java])
你可以用这个指令定义工程名称,并可指定工程支持的语言,支持的语言列表是可以忽略的,默认情况表示支持所有语言。这个指令隐式的定义了两个 cmake
变量:<projectname>_BINARY_DIR
以及 <projectname>_SOURCE_DIR
,这里就是HELLO_BINARY_DIR
和 HELLO_SOURCE_DIR
(所以 CMakeLists.txt
中两个 MESSAGE
指令可以直接使用了这两个变量),因为采用的是内部编译,两个变量目前指的都是工程所在路径/backup/cmake/t1
,后面我们会讲到外部编译,两者所指代的内容会有所不同。同时 cmake
系统也帮助我们预定义了 PROJECT_BINARY_DIR
和 PROJECT_SOURCE_DIR
变量,他们的值分别跟 HELLO_BINARY_DIR
与 HELLO_SOURCE_DIR 一致。为了统一起见,建议以后直接使用 PROJECT_BINARY_DIR,PROJECT_SOURCE_DIR
,即使修改了工程名称,也不会影响这两个变量。如果使用了<projectname>_SOURCE_DIR
,修改工程名称后,需要同时修改这些变量。
set
:
SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
现阶段,你只需要了解 SET 指令可以用来显式的定义变量即可。
比如我们用到的是 SET(SRC_LIST main.c)
,如果有多个源文件,也可以定义成:SET(SRC_LIST main.c t1.c t2.c)
find_package
:
FIND_PACKAGE(<name> [major.minor] [QUIET] [NO_MODULE][[REQUIRED|COMPONENTS] [componets...]])
用来调用预定义在 CMAKE_MODULE_PATH
下的 Find<name>.cmake
模块,你也可以自己定义 Find<name>
模块,通过 SET(CMAKE_MODULE_PATH dir)
将其放入工程的某个目录中供工程使用,我们在后面的章节会详细介绍 FIND_PACKAGE
的使用方法和 Find
模块的编写
add_executable
:
定义了这个工程会生成一个文件名为 hello 的可执行文件,相关的源文件是 SRC_LIST
中定义的源文件列表, 本例中你也可以直接写成 ADD_EXECUTABLE(hello main.c)
。在本例我们使用了${}
来引用变量,这是 cmake
的变量应用方式,但是,有一些例外,比如在 IF
控制语句,变量是直接使用变量名引用,而不需要${}
。如果使用了${}
去应用变量,其实 IF
会去判断名为${}
所代表的值的变量,那当然是不存在的了
target_link_libraries
:
TARGET_LINK_LIBRARIES(target library1 <debug | optimized> library2...)
这个指令可以用来为 target
添加需要链接的共享库,本例中是一个可执行文件,但是同样可以用于为自己编写的共享库添加共享库链接
也许这个讲的更清楚呢 T T
CMakeLists.txt 语法介绍与实例演练
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)