CMake入门教程:构建C++项目完全指南 #
本文简单介绍下CMake的基本使用,掌握这几个知识点你应该可以使用CMake成功构建一个小项目。
在学习CMake之前,我们首先要掌握如何使用命令行构建程序,比如下面这个程序:
// test.cc
#include <iostream>
int main() {
#ifdef HELLO_WORLD
std::cout << HELLO_WORLD << "\n";
#endif
std::cout << "main \n";
}
这一个简单的源文件,如何使用clang构建?
可以这样:
clang++ test.cc -std=c++14 -DHELLO_WORLD=2
如果编译链接成功,会自动在当前目录生成名为a.out的可执行文件,运行时直接./a.out即可,也可以使用-o指定生成可执行文件的名字。
那上面的命令代表什么意思?
clang++不用多说。
test.cc表示源文件的名字。
-std=C++14表示使用的C++标准,上面我使用的是C++14,你也可以改为使用C++11或C++17或20等。
-D表示定义一个宏,-DHELLO_WORLD=2表示定义了一个HELLO_WORLD的宏,它的值是2。
那如果程序复杂点呢,比如这样:
在另一个单独的头文件func.h中声明func,同时在另一个源文件中定义它的实现,这种程序怎么编译?
clang++ test.cc func.cc -std=c++14 -DHELLO_WORLD=2
直接把func.cc加进去即可。
另外,大家平时编译过程中可能会遇到 找不到头文件 的编译失败问题,比如找不到func.h,那怎么解决?
应该在编译时指定源文件中引用的头文件所在的目录,比如func.h在目录funch中, 那怎么指定目录? 可以 使用-I ,这里是大写的I(i),示例如下:
clang++ test.cc func.cc -std=c++14 -I funch -DHELLO_WORLD=2
还有个情况,我们经常会引用一些第三方库,比如我在程序中引用了libxxx.a,它在xxxdir目录中,那怎么链接这个库,这里有两块需要指定,一个是指定链接库所在的目录(使用-L),一个是指定链接库的名字(使用-l,小写的L),可以这样使用:
clang++ test.cc func.cc -std=c++14 -I funch -L xxxdir -lxxx -DHELLO_WORLD=2
还有个情况,比如我还想添加一些编译参数,那可以直接在命令行后面添加:
clang++ test.cc func.cc -std=c++14 -I funch -L xxxdir -lxxx -DHELLO_WORLD=2 -Werror -Wall -fpic等等
通过上面的命令行构建程序,你应该明白了以下几点:
如何指定参与编译的源文件
如何设置C++标准
如何设置并添加编译参数
如何定义宏
如何指定头文件目录
如何指定链接库目录
如何指定要链接哪个库
掌握了上面几点后,再学习CMake就简单了,其实CMake到最后也是会变成命令行来执行。
使用CMake,都需要有个 CMakeLists.txt 文件,可以在这个文件里添加内容,比如要构建上面的程序,可以这样写CMakeLists.txt:
第1行的cmake_minimum_required表示CMake要求的最低版本号,如果你的CMake用到了高版本特有的功能,需要指定版本号要求用户升级才可以使用。
第2行的project(xxx)表示项目的名字是xxx,项目编译链接生成的程序名字就会叫xxx。
第3行的add_definitions,可以用于定义某个宏。
也可以使用第8行和第9行的set (CMAKE_CXX_FLAGS),无脑在后面添加参数,就像命令行一样。
include_directories用于指定头文件目录,类似于命令行中的-I。
link_directories用于指定链接库目录,类似于命令行中的-L。
第14行和第15行的set用于定义变量,而解析变量则使用美元符。
第17行的add_executable用于定义构建可执行程序,指定源文件列表。
第18行的target_link_libraries用于指令链接哪些库,类似于命令行中的-l。
前面说过CMake到最后也会变成命令行去执行,想要看到详细信息可以打开对应的VERBOSE,就是第4行。
那现在执行一下,一般使用CMake都会新建一个build目录,用做工作目录,因为会生成很多中间文件,那我们执行一下:
mkdir build
cd build
cmake ..
make
为什么有cmake ..然后make,因为make命令是通过Makefile来构建的,它只识别Makefile。
而cmake ..就是识别上一级目录中的CMakeLists.txt然后在当前build目录中生成了一个Makefile,供make识别:
这是cmake后的产物:
然后再执行下make:
因为我打开了VERBOSE,所以这里可以看到详细的命令信息,你也完全可以复制上面的命令来执行,也可以生成可执行程序的。