算法部署实战教程,万字长文带你C++一步步实操CMake应用!
仅用于站内搜索,没有排版格式,具体信息请跳转上方微信公众号内链接
以下文章来源于微信公众号:集智书童
作者:小书童
链接:https ://mp. weixin.qq. com/s/4iUTsx_rSjRI93b71YOyLg
本文仅用于学术分享,如有侵权,请联系后台作删文处理
导读
Cmake作为一种构建C++项目的实用工具,却很少有上手教程。那么本文将从实战出发,一步一步教你如何使用cmake工具,让C++工程编译更有效率。
你或许听过好几种Make工具,例如GNUMake,QT的qmake,微软的MSnmake,BSDMake(pmake),Makepp,等等。这些Make工具遵循着不同的规范和标准,所执行的Makefile格式也千差万别。这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的Make工具,就得为每一种标准写一次Makefile,这将是一件让人抓狂的工作。
在linux平台下使用CMake生成Makefile并编译的流程如下:
编写CMake配置文件CMakeLists. txt;
执行命令cmakePATH或者ccmakePATH生成Makefile(ccmake和cmake的区别在于前者提供了一个交互式的界面)。其中,PATH是CMakeLists. txt所在的目录;
使用make命令进行编译。
对于简单的项目,只需要写几行代码就可以了。例如,假设现在我们的项目中只有一个源文件main. cpp,该程序的用途是计算一个数的指数幂。
首先编写CMakeLists. txt文件,并保存在与main. cpp源文件同个目录下:
CMakeLists. txt的语法比较简单,由命令、注释和空格组成,其中命令是不区分大小写的。符号#后面的内容被认为是注释。命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔。
对于上面的CMakeLists. txt文件,依次出现了几个命令:
cmake_minimum_required:指定运行此配置文件所需的CMake的最低版本;
project:参数值是Test_Demo1,该命令表示项目的名称是Test_Demo1。
add_executable:将名为main. cpp的源文件编译成一个名称为Demo1的可执行文件。
之后,在当前目录执行sudocmake.,得到Makefile后再使用sudomake命令编译得到Demo1可执行文件。
同一目录,多个源文件
上面的例子只有单个源文件。现在假如把power函数单独写进一个名为MathFunctions. cpp的源文件里,使得这个工程变成如下的形式:
这个时候,CMakeLists. txt可以改成如下的形式:
唯一的改动只是在add_executable命令中增加了一个MathFunctions. cpp源文件。这样写当然没什么问题,但是如果源文件很多,把所有源文件的名字都加进去将是一件烦人的工作。更省事的方法是使用aux_source_directory命令,该命令会查找指定目录下的所有源文件,然后将结果存进指定变量名。其语法如下:
因此,可以修改CMakeLists. txt如下:
这样,CMake会将当前目录所有源文件的文件名赋值给变量DIR_SRCS,再指示变量DIR_SRCS中的源文件需要编译成一个名称为Demo2的可执行文件。
现在进一步将MathFunctions. h和MathFunctions.cpp文件移动到MyMath目录下。将main. cpp放入src文件里。
对于这种情况,需要在Test_Demo3根目录下编写一个CMakeLists. txt文件,以及分别在项目根目录scr和MyMath目录里各编写一个CMakeLists. txt文件。
Test_Demo3根目录中的CMakeLists. txt:
该文件添加了下面的内容:使用命令add_subdirectory指明本项目包含一个子目录MyMath以及一个子目录src,这样MyMath目录和src目录下的CMakeLists. txt文件和源代码也会被处理。
MyMath子目录中的CMakeLists. txt:
在该文件中使用命令add_library将src目录中的源文件编译为动态链接库。
src子目录中的CMakeLists. txt:
使用命令target_link_libraries指明可执行文件Demo3需要连接一个名为MathFunctions的链接库。
之后的构建模式如下:
CMake允许为项目增加编译选项,从而可以根据用户的环境和需求选择最合适的编译方案。
例如,可以将MathFunctions库设为一个可选的库,如果该选项为ON,就使用该库定义的数学函数来进行运算。否则就调用标准库中的数学函数库。
修改src目录下的CMakeLists文件
我们要做的第一步是在src目录的CMakeLists. txt文件中添加该选项:
其中:
configure_file命令用于加入一个配置头文件config. hpp,这个文件由CMake从config. hpp.in生成,通过这样的机制,将可以通过预定义一些参数和变量来控制代码的生成。
option命令添加了一个USE_MYMATH选项,并且默认值为ON。
USE_MYMATH变量的值来决定是否使用我们自己编写的MathFunctions库。
之后修改main. cpp文件,让其根据USE_MYMATH的预定义值来决定是否调用标准库还是MathFunctions库:
在config目录下编写config. hpp.in文件上面的程序值得注意的是第2行,这里引用了一个config. hpp文件,这个文件预定义了USE_MYMATH的值。但我们并不直接编写这个文件,为了方便从CMakeLists. txt中导入配置,我们编写一个config. hpp.in文件,内容如下:
这样CMake会自动根据CMakeLists配置文件中的设置自动生成config. hpp文件。
现在编译一下这个项目,为了便于交互式的选择该变量的值,可以使用sudocmake-gui命令(该命令会提供一个会话式的交互式配置界面):
从中可以找到刚刚定义的USE_MYMATH选项,打勾为勾选ON,我们可以试试分别将USE_MYMATH设为ON和OFF得到的结果:USE_MYMATH为ON运行结果:
此时config. hpp的内容为:
USE_MYMATH为OFF运行结果:
此时config. hpp的内容为:
CMake也可以指定安装规则,以及添加测试。这两个功能分别可以通过在产生Makefile后使用sudomakeinstall和sudomaketest来执行。在以前的GNUMakefile里,你可能需要为此编写install和test两个伪目标和相应的规则,但在CMake里,这样的工作同样只需要简单的调用几条命令。
首先先在Test_Demo5/CMakeLists. txt文件里添加下面两行:
指明MathFunctions库的安装路径。之后同样修改根目录的CMakeLists文件,在末尾添加下面几行:
添加测试同样很简单。CMake提供了一个称为CTest的测试工具。我们要做的只是在项目根目录的CMakeLists文件中调用一系列的add_test命令。
上面的代码包含了四个测试。第一个测试test_run用来测试程序是否成功运行并返回0值。剩下的三个测试分别用来测试5的平方、10的5次方、2的10次方是否都能得到正确的结果。其中PASS_REGULAR_EXPRESSION用来测试输出是否包含后面跟着的字符串。
让我们看看测试的结果:
如果要测试更多的输入数据,像上面那样一个个写测试用例未免太繁琐。这时可以通过编写宏来实现:
关于CTest的更详细的用法可以通过使用man1ctest命令参考CTest的文档。
支持gdb
让CMake支持gdb的设置也很容易,只需要指定Debug模式下开启-g选项:
之后可以直接对生成的程序使用gdb来调试。
有时候可能要对系统环境做点检查,例如要使用一个平台相关的特性的时候。在这个例子中,我们检查系统是否自带pow函数。如果带有pow函数,就使用它;否则使用我们定义的power函数。
给项目添加和维护版本号是一个好习惯,这样有利于用户了解每个版本的维护情况,并及时了解当前所用的版本是否过时,或是否可能出现不兼容的情况。
首先修改顶层CMakeLists文件,在project命令之后加入如下两行:
分别指定当前的项目的主版本号和副版本号。
之后,为了在代码中获取版本信息,我们可以修改config. hpp.in文件,添加两个预定义变量:
这样就可以直接在代码中打印版本信息了:
本节将学习如何配置生成各种平台上的安装包,包括二进制安装包和源码安装包。为了完成这个任务,我们需要用到CPack,它同样也是由CMake提供的一个工具,专门用于打包。
修改MyMath子目录中的CMakeLists. txt:*
将src目录中的源文件编译为静态链接库。
在再在顶层的CMakeLists. txt文件尾部添加下面几行:
上面的代码做了以下几个工作:
导入InstallRequiredSystemLibraries模块,以便之后导入CPack模块;设置一些CPack相关变量,包括版权信息和版本信息,其中版本信息用了上一节定义的版本号;导入CPack模块。接下来的工作是像往常一样构建工程,并执行cpack命令。生成二进制安装包:
生成源码安装包:
我们可以试一下。在生成项目后,执行sudocpack-CCPackConfig. cmake命令:
此时会在该目录下创建3个不同格式的二进制包文件:
这3个二进制包文件所包含的内容是完全相同的。我们可以执行其中一个。此时会出现一个由CPack自动生成的交互式安装界面:
Ifyouwanttostopextracting,pleasepress. 就是个测试文件,不需要啥子说明,就是一个pow幂函数的实现!!!!
完成后提示安装到了Demo8-1. 0.1-Linux子目录中,我们可以进去执行该程序:
修改MyMath子目录中的CMakeLists. txt:*
将src目录中的源文件编译为动态链接库。
剩下的操作和静态的一样的,注意的是最后那里。
说明找不到库,因为采用的是动态链接库,所谓动态链接是在运行时链接,编译链接的时候是直接告诉了GCC库的位置,因此会成功,而运行是如果不告诉操作系统库在哪个位置,当然找不到这个库,程序也就不能运行。因此要告诉操作系统库在哪个地方,linux使用LD_LIBRARY_PATH告诉系统库在哪个地方。(LD_LIBRARY_PATH是Linux环境变量名,该环境变量主要用于指定查找共享库(动态链接库)时除了默认路径之外的其他路径)。
保存退出后,然后在控制台执行以下命令:
运行程序就能够执行了。
关于CPack的更详细的用法可以通过使用man1cpack命令参考CPack的文档。
欢迎加入《AI未来星球》,一起成长
扫描下方二维码即可加入~
真诚分享AI落地过程(AI商机->项目签约->算法开发->产品开发->实施运维)中的各方面经验和踩过的坑。
你可以获得什么?
1、大白之前花费10W+购买,AI行业各场景私有数据集下载,星球内倾情分享;2、AI行业研发、产品、商业落地问题咨询(目前AI公司创业中),都可获高质量解答,有效期一年,无限次提问,有问必答。3、定期邀请AI行业各类嘉宾分享,创业/商业等方面的经验!
帮助你解决遇到的实际问题,升职加薪!
大家一起加油!