利用vs2017 CMake开发跨平台C++项目实战
对于windows程序员来说,在linux上开发C++程序会非常困难,一来没用过makefile,其语法非常生涩难懂,二来vs之外的IDE,其易用性与vs相差甚远,宇宙第一IDE不是盖的。致使C++不同于其他编程语言,硬生生催生出Windows程序员和Linux程序员两个群体,直到有了CMake。
常用开源库的同学想必对CMake非常熟悉,它可以在Linux上可以自动生成makefile,在Windows下可以生成vs解决方案sln,对于大规模跨平台项目绝对是首选,只不过Linux程序员用的多。相对于makefile,CMake语法要简单的多,一周包教包会,走向人生巅峰。现在程序员的福音来了,visual studio在2017以后已经支持了CMake语法,使用vs2017可以在windows下写程序,在linux下编译,真的很方便。虽然现在的版本还不太成熟,偶尔会出现一些迷之错误,但相信以后这都不是事。真希望有一天,大家都用上vs2017。
废话不多说,我以实战入手,从我的代码搬迁开始说起,我原先的代码是用vs2013开发的,第三方库头文件和库文件的管理都是通过vs属性页管理的,程序间互相依赖是通过引用完成的。如图所示:
想必这些对windows程序员都非常熟悉,vs就是通过这样管理项目的。我下面逐步介绍一下我这个工程是如何搬迁到linux上运行的。
一、建立工程目录
如果你在装vs2017的时候勾选了cmake,点击新建->项目时会出现cmake选项,点击确定,建立一个工程文件夹。
cmake会自动为我们创建如下文件,CMakeLists.txt就是管理当前文件夹下文件的配置文件,由于我一个文件夹里放一个工程,因此其地位相当于vs的vsproject,好像其不能改名,只能这么命名,不管它。子文件夹cmake_test是自动生成的,我并不打算将我的根目录叫这个名字,删除之:
新建我的源代码文件根目录src,并向其添加CMakeLists.txt
打开根目录的CMakeList.txt,其中可以写入对整个工程的配置:
cmake_minimum_required用来设置cmake的最低版本,如果所使用低于最低版本会报错。project用来设置整个工程的名字,add_subdirectory用来对子目录进行管理,这里我们只有一个子目录src,将其加进来。cmake语法不区分大小写,这里为了与其他语法相区别,统一都用大写。set命令通常用来设置变量,CMake自身有许多预定义变量,可以通过set给它们赋值,如CMAKE_MOULE_PATH里面就指向了.cmake文件的搜索目录,这通常会被用在第三方库的搜索上面,它同时也有默认值,如CMAKE_SOURCE_DIR就是指向了根目录,这里就是将根目录下cmake文件夹作为第三方库搜索文件所在目录。
二、加入源代码
在子文件夹src中迁移源代码,按工程新建文件夹
src文件夹下的CMakeList.txt用来对源代码文件夹进行管理,其cmake代码如下:
很简单,把各自子项目的源代码文件夹加进来就可以了。将vs各工程内的.h、.cpp都复制到cmake子项目文件夹下,并在其内新建CMakeLists.txt
其文件夹下的CMakeLists.txt是对本工程下源代码文件的管理
PROJECT就是该工程的名字,FILE是文件操作命令,其作用是将所有cpp文件存入base_src变量内,GLOB选项将会为所有匹配查询表达式的文件生成一个文件list,并将该list存储进变量variable里,如果不指定GLOB,就要将所有cpp都列进来了,一般如果我们所有cpp都参与编译,就用GLOB都包含进来就可以了。ADD_LIBRARY的主要作用就是将指定的源文件生成链接文件,然后添加到工程中去,该指令常用的语法如下:
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2] [...])
其中<name>表示库文件的名字,该库文件会根据命令里列出的源文件来创建。而STATIC、SHARED和MODULE的作用是指定生成的库文件的类型。STATIC库是目标文件的归档文件,在链接其它目标的时候使用。SHARED库会被动态链接(动态链接库),在运行时会被加载。MODULE库是一种不会被链接到其它目标中的插件,但是可能会在运行时使用dlopen-系列的函数。默认状态下,库文件将会在于源文件目录树的构建目录树的位置被创建,该命令也会在这里被调用。
ADD_LIBRARY (${PROJECT_NAME} SHARED ${base_src})
这里的${PROJECT_NAME}就是工程名,也就是Base,这里$通常用来引用变量,这个语法倒是和vs一样。base_src就是刚才的源文件列表,由于我的工程都是动态链接库,因此,这里用了SHARED。
INCLUDE_DIRECTORIES用来设置头文件的搜索目录,也就是跟vs中的VC++目录一样的功能,几乎每个工程都有这么一句。
值得注意的是,通常我们在windows设置动态链接库的时候,都要设置类或函数的导出符号,而Liunx不需要这么做,通常我们可以用宏进行控制,在vs工程中,默认会定义预编译宏_WINDOWS,通常拿这个就可以控制windows平台和Linux了。
CMakeLists.txt中ADD_DEFINITIONS(-DBASE_EXPORTS)就是为了在windows平台下设置BASE_EXPORTS这个宏,使其导出符号而设置的。
三、第三方库设置
我们在做项目的时候通常都会用到很多开源库,vs的通用做法是将其写到工程文件中,cmake也一样,也会写到CMakeLists.txt文件中,它还有更强大的搜索功能,可以不必指定第三方库的绝对路径。正好我的工程Log里就用到了第三方库Log4cpp,我将演示如何设置它。在Log子项目文件夹下新增CMakeLists.txt,其内容有:
TARGET_LINK_LIBRARIES命令是在本项目中对其他工程的依赖设置的,这里设置其依赖Base工程,这就相当于vs里的工程引用了,CMake根据项目间的依赖设置项目生成顺序。
FIND_PACKAGE就是用来发现第三方库的,它首先会在模块路径中寻找Find.cmake,这里就是查找FindLog4cpp.cmake,模块路径就是CMAKE_MOULE_PATH指定的那个。
.cmake文件里其实写的也是cmake语句,你完全可以不用它,自己在CMakeLists.txt里写,不过写到它里面会更整洁明了。通常比较流行第三方库的Find.cmake文件不用自己手写,你总是能在网上找到它。我将我所有可能用到的第三方库Find.cmake都放到这里。
IF(Log4cpp_FOUND)
INCLUDE_DIRECTORIES(${Log4cpp_INCLUDE_DIR})
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${Log4cpp_LIBRARY})
ELSE()
MESSAGE(STATUS "CANNOT FIND LOG4CPP LIBRARY")
如果找到了Log4cpp,则Log4cpp_FOUND会赋值为true,它其实是FindLog4cpp.cmake里面的一个变量,同时将Log4cpp_INCLUDE_DIR加入其头文件搜索路径,Log4cpp_LIBRARY作为其依赖库。它俩需要在外部设置。如果找不到MESSAGE会输出一条错误,它也被经常用来打印调试信息,总之是非常有用的。打开FindLog4cpp.cmake看一看:
可以看到里面的语法跟外面的是一模一样的。
四、在VS2017中编译CMake工程
用过CMake的都知道,在windows上用cmake生成sln时,就会给它设置第三方目录,也就是给第三节的Log4cpp_INCLUDE_DIR等变量赋值,赋值成功后,可以在工程目录下生成各个vs版本的sln文件,再编译它。
而在vs2017中已经支持直接打开CMakeLists.txt了,那么第三方目录在哪设置,sln又生成在哪里了呢。在根目录中右击CMakeLists.txt选择“配置cmake”,这时在根目录下会生成CMakeSettings.json文件,CMakeLists.txt里用到的配置都可以写在这里。
其中,buildRoot就是sln生成目录了。variables就是用来对CMake中用到的变量进行赋值。这里我把第三方库的编译结果,都放在根目录的third_party文件夹中,这跟我们通常的做法没什么两样。
将变量都设置正确后,CMake工程就可以在vs2017上编译成功了。其他调试之类的与非CMake工程没什么区别。
五、在Linux上编译
当我们在Windows上代码都弄好了之后,剩下的只是在Linux上编译而已。Linux对第三方库的管理比Windows强大的多,常用库输入sudo apt-get install就可以安装了。找不到也没关系,只需要下载后直接编译就好,不像windows还要生成sln才能编译。还以Log4cpp为例,从github上下载好后,键入如下命令:
cd log4cpp
mkdir build
cmake ..
make
make install
Log4cpp就安装完毕了
编译结果通常都会放到/user/include、/user/local/user之类的文件夹下,所以用FindCMake是能直接找到的。第三方库全部下载好之后,就进入根目录文件夹,键入类似命令:
cd log4cpp
mkdir build
cmake ..
make
大功告成
更多推荐
所有评论(0)