CMake快速上手

目录

一、CMake中常量定义

1.PROJECT_NAME

2.PROJECT_SOURCE_DIR、_SOURCE_DIR

3.PROJECT_BINARY_DIR、_BINARY_DIR

4.CMAKE_CURRENT_SOURCE_DIR

5.CMAKE_CURRENT_LIST_LINE

二、从实际应用开始!

2.1 单个源文件

2.2 头文件虽迟但到

2.3 多文件夹组织的细致工程

2.4 什么!还要用OpenCV?(添加第三方库)


一、CMake中常量定义

在CMake语法中定义了一些常量。这些常量经常被${变量名} 这种奇怪的方式调用。必须承认,这种方式确实非常独特。

当然,${}是CMake调用变量的通用形式,并不仅限于调用常量。当使用用户自定义的变量时,也是以这种方式调用。

在CMake中,比较常见的一些常量,都有很重要的含义。毕竟过于偏僻邪门的含义没必要声明成常量吧?

1.PROJECT_NAME

这个变量表示工程名。通常情况下,工程名通过project(“projectname”)定义。在使用project()定义工程名之后,PROJECT_NAME会自动等于定义的”projectname”。如果不定义”projectname”, CMake不会报错。会自动给PROJECT_NAME赋一个值,这个值为Project。但是不使用project(“projectname”)是非常不建议的。因为在开发比较大工程时,通常会包含几个小工程。没有小工程名,在大工程是不能把小工程包含进来的!

2.PROJECT_SOURCE_DIR、<projectname>_SOURCE_DIR

这两个常量可以表示同一种含义:当前工程所在目录。注意第二个比较奇怪的表示形式,其中的<projectname>这部分,需要用${PROJECT_NAME}这个来代替。也就是说第二个量的表示形式完整应为${PROJECT_NAME}_SOURCE_DIR。注意这仅是变量名,如果要调用这个变量,依旧要使用${${PROJECT_NAME}_SOURCE_DIR}。过于复杂了。

3.PROJECT_BINARY_DIR、<projectname>_BINARY_DIR

这两个常量同样表示同一种含义:CMake的执行目录。编译生成的文件一般也放在这个文件夹下。

4.CMAKE_CURRENT_SOURCE_DIR

该常量表示当前CMakeLists.txt文件所在的路径。这里要对CMakeLists.txt说明,这个文件是敲CMake代码的指定文件。该文件的名称、后缀都是不可改变的!

5.CMAKE_CURRENT_LIST_LINE

该常量可以得到当前代码在CMakeLists.txt中的行数。

二、从实际应用开始!

2.1 单个源文件

先来一个简单的提升一下成就感!只用三句话,让编译器输出一个Hello World!

首先敲一个main.c,让它输出”hello world”

在main.c所在的文件夹下,创建自己的CMakeLists.txt文件,开码

哦?为什么不是三句话?是这样的,以#开头的是cmake语法中的注释语句,没有实际作用。所以上图代码中,真正起作用的是第2,4,6行。每一行的作用都有与其对应的注释做说明。在编译完后运行CMakeLists.txt文件,生成makefile,存放编译生成的文件。一般情况下,在工程目录下的build文件夹下。

 

最终的运行结果如下图 

很简单是不是,又简单又快速,get到新的工程编译方法。

那就会有吴彦祖说了,谁用这么简单的工程文件啊?工程里面有头文件怎么办啊?

我知道你很急,但你先别急。接下来的部分,来讲一下如何在CMakeLists.txt中添加有效的头文件。

2.2 头文件虽迟但到

 包含头文件之后,工程的文件架构如下图

CMakeLists.txt中内容如下 

 

再进一步,当整个工程中不止包含一个源文件时,例如当整个工程架构如下:

工程中有一个MyTest.h,其中定义了一个类,MyTest.cpp用于实现这个类。然后在main文件中调用。按照上面的思路,只需要在add_executable()中继续加文件就可以了,像这样:

 

 那这时候就会出现一个问题,当工程中的源文件有几十个,这时候难道还要一个一个敲上去?那当然不是这样了。CMake提供了一种更简洁的添加源文件、头文件的方式。

解释一下,这里和将所有文件一股脑丢到add_executable()中不同,此处的add_executable()只调用了两个变量一个是工程名,另一个是SRC。调用定义的变量名,一定要使用${}!SRC是使用aux_source_directory()定义的。这里面也包含两个参数,一个是. 另一个是SRC。.的含义是当前目录。所以这个函数的功能就是把把当前目录下的源文件,输出到SRC变量中。使用message(${SRC})打印SRC变量的值,可以看到它的值为

此处补充一个函数message(),类似printf()函数。可以输出变量值、字符串等信息。

源文件使用SRC变量完美替代,那头文件呢?头文件的包含,CMake也提供了相关的函数实现相关功能。上图代码中使用的是include_directories()一般函数的参数为头文件所在的目录。因为在当前工程中头文件所在目录就是工程的目录,所以可以用${PROJECT_SOURCE_DIR}变量来替代。这样就自动将头文件添加进去了,无需再在add_executable()中添加额外的头文件参数。

CMAKE还提供了另一种头文件引用方式。针对生成的文件添加头文件,具体操作如下:

target_include_directories()包含三个参数。第一个参数是生成的目标。该目标仅能为add_executable()中生成的可执行文件或者add_library()生成的库文件。add_library用法后面再说。这里注意该目标属性即可。

第二个参数是包含的头文件应用范围。该参数共有三个值:PUBLIC, PRIVATE, INTERFACE。当使用add_executable()时,可以填的参数只有PUBLIC和PRIVATE,似乎没有什么区别。如果有吴彦祖对此非常了解,麻烦告知我。只有当对add_library()生成的库文件添加三种属性时候会有区别。PUBLIC是表明当前库文件不仅使用头文件也将头文件的接口暴露给外面。PRIVATE是仅供自己的库文件使用头文件。INTERFACE表明该接口对外,库文件不用。

第三个参数就是头文件所在的路径了。

针对CMAKE提供的两种头文件包含方式,比较推荐第二种。第二种头文件包含更具有指向性。当在一个CMakeLists.txt中使用include_directories()添加头文件,该文件内所有生成的目标都将自动包含这些头文件。而使用target_include_directories()则可以指明哪些目标包含特定的头文件,看起来逻辑更加清晰。

2.3 多文件夹组织的细致工程

 

 这个文件结构应该能符合大多数工程的要求。其中include存放头文件,src存放源文件。这里面CMakeLists.txt写法其实和2.2中非常相似。

相信聪明的吴彦祖已经可以发现端倪了。当对源文件和头文件分别用不同文件夹存储时,只需要在定义SRC变量和添加头文件时候加上对应的文件夹路径。这个路径是相对于工程所在目录的路径即可。比如此处的头文件夹位于工程目录下的include文件夹中,所以只需要在添加头文件时候写到include即可。同样的采用另一种添加头文件的方式,写法如下

 

在填写路径时,有一个需要注意的地方。如果直接复制Windows下的文件路径,例如:D:\OpenCV\opencv\build\x64\vc16\bin。这样的路径时不能被CMake识别的。CMake中的格式应该是D:/OpenCV/opencv/build/x64/vc16/bin。吴彦祖们肯定已经发现了区别。

2.4 什么!还要用OpenCV?(添加第三方库)

在开发过程中,尤其是C++开发,经常要使用第三方的库文件来提升开发效率。例如经常使用的OpenCV库,更是C++在图像处理应用上绕不开的第三方库。用OpenCV举例,说明一下在CMake中添加第三方库的方式。

首先需要在电脑中正确安装OpenCV,正确添加环境变量。开始敲CMake。

 

 

使用find_package()找OpenCV的库文件,如果找到,OpenCV_FOUND变量会被置为真。OpenCV_开头的几个变量会被赋值。这几个变量的具体含义可以参见OpenCV的OpenCVConfig.cmake文件。这个文件位于OpenCV根目录下的build文件夹内。

 

对每个值都好奇的话,可以通过message()打印所有变量值。

有个要注意的地方是我安装的OpenCV版本是4.7。所以在使用find_package()时候加上了4.7版本号。不加应该问题也不大。网络上别人写的教程中,OpenCV_INCLUDE_DIRS这个变量可能会被写成OpenCV_INCLUDES_DIRS。我猜测可能是不同版本的变量名定义不同。所以具体的变量名定义还是要以自己安装的OpenCV的配置文件为准。

再回来看CMakeLists.txt。可以通过include_directories()添加头文件,通过target_link_libraries()添加库文件。在添加时候,建议通过if判断OpenCV_FOUND变量值。如果该值没有被置为真,则不进行相关添加。但是我的代码中把include_directories()注释掉了,此时的OpenCV仍然是可以用的。这种做法的来源同样是来自OpenCVConfig.cmake:

 

最后在main中测试是否将OpenCV成功添加,敲一敲测试代码:

 

run!

 

小刘鸭和鼻孔猫的图像就显示出来啦!

在测试OpenCV时,使用imshow()函数,后面不建议使用system(“pause”)。这个函数会导致系统暂停,imshow不能完成相关库文件调。导致的结果就是图片显示不出来,对话框灰蒙蒙的一片。使用OpenCV自带的waitkey(),就没有问题啦!

如果需要源码支持或者其他问题咨询,欢迎留言私信!

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值