CMake
本文主要内容如下:
-
cmake工程的目录组织及基本的编写规则
-
对比cmake 编译为DEBUG版本和RELEASE版本的区别 (文件的执行效率,以及文件大小)
现在养成了一个习惯,学了点东西习惯性的想要写下来,不管内容是简单还是复杂,是入门还是进阶,写下来方便以后回顾与总结,万丈高楼平地起,希望坚持耕耘下去。
CMake和Makefile对于C/C++程序员应该不陌生,这是应该熟悉和掌握的。简单来说,C/C++程序通过编译和链接后才能变成能够在CPU上运行的机器码。一般的IDE工具都帮我们封装了相应的功能,因此对于高级一点的语言,类似于C#,java等,一般不经常打交道。但是对于C/C++程序员,还是有必要深入掌握。
本文主要介绍更高级的编译工具CMake,而Makefile另外写文章学习。
让我们回忆下最简单的C++版本的helloworld,我们只有一个main.cpp文件。在Linux下,我们的g++编译器会帮助我们编译该文件为可执行文件,从而我们执行该文件即可运行我们的程序。一般情况下,我们会使用如下的命令进行编译:
g++ helloworld.cpp -o helloworld
但是随着程序文件的增加,我们难道要一条条命令的去编译每个文件吗?显然是不太可能的,因此诞生了Makefile文件。Makefile的具体介绍见另外的文章,Makefile类似于批处理文件,自动帮我们执行类似上面的命令,同时,最主要的是,它能够帮助我们自动编译那些需要编译的文件,而其他文件只需要链接即可。
但是Makefile在不同平台上有不同的编写规则,无法做到一次编写任意使用。因此,CMake工具诞生了,这个工具可以帮助我们自动构建对应平台的工程,并生成相应的Makefile文件,然后就可以进行编译了(编译的结果一般有三种:可执行程序,静态库,动态库)。
举个例子吧。如下的目录结构的工程:一般项目的根目录会有一个总的CMakeLists文件。在该文件中通过add_subdirectory(sample)可以添加子目录的CMakeLists;
Sample目录如下:子目录也会有对应的CMakeLists文件,并包含进一步的子目录。
Sample目录的CMakeLists文件内容:
Helloworld文件夹的CMakeLists文件内容如下:其中project指定工程名,set定义src变量代表了源文件的路径,其中CMAKE_CURRENT_SOURCE_DIR表示当前工程cmakeList的路径,add_executable用于生成可执行文件。
再来看看linkage目录下的CMakeLists文件内容:该目录下的main.cpp引用了base64目录下的静态库。其中include_directories用于包含外部库的目录。Target_link_libraries用于添加链接的外部库(仅包含外部库的头文件是不行的,会包undefined reference错误)。但要注意,这里based64和linkage属于同一个项目,因此可以直接在Target_link_libraries中添加即可。如果是外部静态库,则需要用下图2所示的方式;但是如果是链接编译器自带的外部库,则不需要link_directory()命令。
编译静态库:base64下的文件:
编译动态库:base64_dynamic文件:
动态库生成时,会生成.dll.a文件,这个静态库其实是导入库,程序链接的时候其实是链接的该文件,但是程序运行的时候,会去加载.dll动态库(因此需要把该dll动态库拷贝到链接该库的工程目录linkage下)。
DEBUG版本和RELEASE版本的区别
还有一点想要说的,就是编译时的选项DEBUG和RELEASE版本的区别。
考虑如下的C++代码,这段代码很简单,就是执行一个很长的循环,用于测试时间。
int count = 1;
const int MAX_LOOP = 10000 * 10000;
std::chrono::steady_clock::time_point beg = std::chrono::steady_clock::now();
for (int i = 0; i < MAX_LOOP; ++i) {
++count;
}
std::chrono::steady_clock::time_point end= std::chrono::steady_clock::now();
std::cout <<" Time difference = " << std::chrono::duration_cast<std::chrono::milliseconds>(end - beg).count() <<std::endl;
我们编译该程序的cmakeLists文件内容如下:
cmake_minimum_required(VERSION 3.5)
project(demo1)
set(CMAKE_CXX_STANDARD 11)
set(SOURCE_FILES main.cpp)
add_executable(demo1 ${SOURCE_FILES})
cmake 默认的是把程序编译为RELEASE版本,下面我们显示的给出DEBUG版本
我们可以看到执行一亿次耗时 194 ms, 文件大小大概45 KB。
我们在看下RELEASE模式下:
可以看到耗时,低于 1 ms,而且文件大小只有9.2 KB。
我们可以在CMakeLists.txt添加如下行,查看cmake默认的编译模式:
message(“default build type is ${CMAKE_BUILD_TYPE}”)
当然我们也可以在CMakeList.txt设置模式:
message(“default build type is ${CMAKE_BUILD_TYPE}”)
set(CMAKE_BUILD_TYPE DEBUG)
message(“after set, build type is ${CMAKE_BUILD_TYPE}”)