了解 CMake
如果你需要经常看众多开源的项目,尤其是 C/C++编写的项目,你一定要学会 CMake的基本使用。
没有为什么
安装
在 macOS上,你可以直接通过 homebrew安装 CMake,在其他 Linux发行版上,你也可以通过对应的包管理器安装。
Hello World
创建一个目录,里面放一个非常简单的源代码文件,叫做 main.c
1 |
|
在同级目录中,添加一个 CmakeLists.txt文件,内容如下:
1 | cmake_minimum_required(VERSION 2.8) |
然后,在你的代码目录里面:
1 | mkdir .build |
一通猛如虎的操作后你会发现刚才写的代码跑出来了
Hello World解读
C代码我就不多做介绍了,直接看 CMakeKLists.txt文件。
“cmake_minimum_required” 表示最小可使用的 CMake版本,如果你安装的 CMake小于 2.8是没法 “cmake ..”的。
“project(cmakeTutorial)” 表示给你当前的项目命名
“add_executable(bin main.c)” 表示当前项目目标是编译到可执行的 bin文件中去,源码实现是 main.c。
至少通过设定编译目标,我们实现了一次 C代码的 CMake编译。 但很明显只编译一个文件不是我们想要的,一个文件直接命令行调用 clang可能还更快点。
多源文件编译
为了演示一下多文件编译,我们再把 printf 给拆分成一个单独的函数试一下,创建 hello.h
1 |
|
创建 hello.c
1 |
|
修改 main.c
1 |
|
然后,我们只需要把 CMakeLists.txt中的 add_executable里面再添加一个 hello.c就好了
1 | cmake_minimum_required(VERSION 2.8) |
你再在 .build目录执行一遍猛如虎的操作试试,还是能编译运行成功的。
但是假如我有 N个源文件咋办,手动一个一个太麻烦了,可以这样改:
1 | cmake_minimum_required(VERSION 2.8) |
用了 CMakeLists.txt的内置函数 aux_source_directory,扫描一个目录的源代码文件,赋值给一个变量。(你始终记住源码文件是 .c/.cc/.cpp 这种实现文件)
但是把所有代码(包括头文件)放在一个目录下面很糟糕,看起来像是菜鸟写的。我们接下来实现一下多个目录。
多目录编译
假如我创建了一个 “hello”目录,并且把 hello.h , hello.c拖了进去,根据上面的经验,你可能会想 CMakeLists.txt这么写:
1 | cmake_minimum_required(VERSION 2.8) |
但是,转折来了。但是,你通常分目录的时候是为了代码分模块写的,那么子目录里面文件越多, 这看起来就越糟糕(强行糟糕) 通常情况是因为你的一个子模块希望能单独编译出去用。所以我们可以把子模块单独编译成库,给主项目用。
编译和链接静态库
在 hello目录里面添加一个 CMakeLists.txt
1 | cmake_minimum_required(VERSION 2.8) |
然后我们把原来的那个 CMakeLists.txt修改一下:
1 | cmake_minimum_required(VERSION 2.8) |
这样就可以了。
add_subdirectory会在主 cmake时自动 cmake子目录,而子目录就正常写就可以了。
hello目录指定了自己的源文件编译成一个静态库叫 hello,然后主目录的 CMakeLists.txt里面指定了最后需要进行 target_link_libraries的链接。
而且,你在 .build目录看到的编译产物很明显也能见到 libhello.a
如果你想编译出一个动态库,只需要在 add_library的库名称后面加上 SHARED即可,如 “add_library(hello SHARED ${SRCFILES})”
头文件
在把子模块作为库链接后,你很明显会疑惑:我们平时用库都不会去 care库的头文件放在哪个目录,因为直接配在了 search path里面,那么 cmake怎么配呢。很简单,以上面为例, 你只需要添加一行
include_directories(hello)
这样你在 main.c 里面直接就可以 #include “hello.h”了,不用 care具体目录。
编译参数
这一部分并不想提多少,只是想告诉大家有这么个东西存在。比如你想设置 C++ Version为 11,那么你可以这样写:
1 | set(CMAKE_CXX_STANDARD 11) |
其实概念上 CMAKE_CXX_STANDARD 是 cmake的一个内置变量, set就是用于设置变量值的函数。同样地你也可以设置 cxx flags
1 | set(CMAKE_CXX_FLAGS '-w') |
更多的其他内置变量或者参数你可以参考 CMake官方文档,其实有需要的时候就可以直接 Google一下。
了解 CMake其实是用于阅读 C/C++项目的一种非常简单有效的手段,这为后面了解 LLVM项目打下一个基础。