CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object)).它的作用和qt的qmake是相似的。
C/C++程序员肯定离不开Makefile和Cmake,因为如果对这两个工具不熟悉,那么你就不是一个合格的C/C++程序员。本文对Makefile和Cmake,及它们的使用进行了详细的介绍,本文的目录如下:
一、Makefile详解
1.1 Makefile语法
1.2 Makefile示例
二、Cmake详解
2.1 Cmake语法
2.2 Cmake示例
一、Makefile详解
Makefile描述了整个工程的编译、连接等规则,makefile定义了一些列规则来指定,哪些文件需要编译以及如何编译、需要创建哪些库文件以及如何创建这些库文件、如何产生我们想要的可执行文件。使用Makefile,整个工程都可以完全自动化编译。而且Makefile 可以有效的减少编译和连接的程序,只编译和连接那些修改的文件。
1.1 Makefile语法
1.1.1
Makefile包含了五个重要的东西:显示规则、隐晦规则、变量定义、文件指示和注释。
1. 显示规则:显示规则说明了,如何生成一个或多个目标。这是由Makefile指出要生成的文件和文件依赖的文件。
2. 隐晦规则:基于Makefile的自动推导功能
3. 变量的定义:一般是字符串
4. 文件指示:一般是在Makefile中引用另外一个makefile文件;根据某些规则指定Makefile中有效的部分;多行
5. 注释:#指示注释
Makefile有三个非常重要的变量:$@、$^、$#,它们的含义如下:
$@ ---目标文件
$^ ---所有依赖文件
$< ---第一个依赖文件
.PHONY ---伪目标文件
Makefile的执行过程如下:
1. 在当前目录下寻找Makefile或makefile。
2. 找到第一个文件中的第一个目标文件,和目标文件依赖的.o文件。
3. 如果.o文件不存在,或是后面.o文件比target文件更新,那么它就会执行后面的语句来生成这个文件。
4. 最后makefile会根据.o文件依赖的.h和.c文件生成.o文件。
1.1.2
注意:
1. clean不要放在target前面。
2. -rm edit $(objects) 忽略某些文件的问题。
3. Makefile中的命令,必须以[Tab]键分割。文件之间最好使用空格分割。
4. -I 或 --include-dir 参数,那么make就会在这些目录下去寻找。
5. -L 相当于load lib dir, -lfb303 相当于libfb303.so
1.1.3 g++编译命令:
1. -g 相当于debug
2. -Wall 相当于忽略warnning
3. -O1~3 相当于优化级别
4. -lpthread多线程
5. -j8 多线程编译
6. -D相当于宏定义,-D_YUQIANG,那么#ifdef _YUQIANG就是True的。
1.2 Makefile示例
[cpp] view plain copy
二、CMake详解
CMake是一个夸平台的安装(编译)工具,可以简单的语句描述所有平台的安装(编译过程)。它能输出各种各样的makefile或者project文件,能测试编译器所支持的c++特性,类似UNIX下的automake。
2.1 Cmake语法
1. project name
PROJECT( project name )
2. 头文件路径
INCLUDE_DIRECTORIES( include )
3. 设置环境变量的值
SET( TEST_DIR ${DIR_SRCS})
4. 设置外部库
SET(LIBRARIES libm.so)
5. 设置可执行文件路径
ADD_EXECUTABLE( ../bin/bin ${TEST_DIR})
6. 设置链接库
TARGET_LINK_LIBRARIES(../bin/bin ${LIBRARIES})
7. 设置代码子目录
ADD_SUBDIRECTORY
2.2 CMake示例
[cpp] view plain copy
1.CMake编译原理
CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多。CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt文件转化为make所需要的makefile文件,最后用make命令编译源码生成可执行程序或共享库(so(shared object))。因此CMake的编译基本就两个步骤:
1. cmake 指向CMakeLists.txt所在的目录,例如cmake .. 表示CMakeLists.txt在当前目录的上一级目录。cmake后会生成很多编译的中间文件以及makefile文件,所以一般建议新建一个新的目录,专门用来编译, mkdir build cd build cmake .. make 2. make 根据生成makefile文件,编译程序。
2.使用Cmake编译程序
我们编写一个关于开平方的C/C++程序项目,即b= sqrt(a),以此理解整个CMake编译的过程。
a.准备程序文件
文件目录结构如下:
. ├── build ├── CMakeLists.txt ├── include │ └── b.h └── src ├── b.c └── main.c
b.编写CMakeLists.txt
接下来编写CMakeLists.txt文件,该文件放在和src,include的同级目录,实际方哪里都可以,只要里面编写的路径能够正确指向就好了。CMakeLists.txt文件,如下所示:
1 #1 .cmake verson,指定cmake版本 2 cmake_minimum_required(VERSION 3.2 ) 3 4 #2 .project name,指定项目的名称,一般和项目的文件夹名称对应 5 PROJECT(test_sqrt) 6 7 #3 .head file path,头文件目录 8 INCLUDE_DIRECTORIES( 9 include 10 ) 11 12 #4 .source directory,源文件目录 13 AUX_SOURCE_DIRECTORY(src DIR_SRCS) 14 15 #5 .set environment variable,设置环境变量,编译用到的源文件全部都要放到这里,否则编译能够通过,但是执行的时候会出现各种问题,比如" symbol lookup error xxxxx , undefined symbol " 16 SET(TEST_MATH 17 ${DIR_SRCS} 18 ) 19 20 #6 .add executable file ,添加要编译的可执行文件 21 ADD_EXECUTABLE(${PROJECT_NAME} ${TEST_MATH}) 22 23 #7 .add link library,添加可执行文件所需要的库,比如我们用到了libm.so(命名规则:lib+name+.so),就添加该库的名称 24 TARGET_LINK_LIBRARIES(${PROJECT_NAME} m)
CMakeLists.txt主要包含以上的7个步骤,具体的意义,请阅读相应的注释。
c.编译和运行程序
准备好了以上的所有材料,接下来,就可以编译了,由于编译中出现许多中间的文件,因此最好新建一个独立的目录build,在该目录下进行编译,编译步骤如下所示:
mkdir build cd build cmake .. make
操作后,在build下生成的目录结构如下:
├── build │ ├── CMakeCache.txt │ ├── CMakeFiles │ │ ├── 3.2 .2 │ │ │ ├── CMakeCCompiler.cmake │ │ │ ├── CMakeCXXCompiler.cmake │ │ │ ├── CMakeDetermineCompilerABI_C.bin │ │ │ ├── CMakeDetermineCompilerABI_CXX.bin │ │ │ ├── CMakeSystem.cmake │ │ │ ├── CompilerIdC │ │ │ │ ├── a.out │ │ │ │ └── CMakeCCompilerId.c │ │ │ └── CompilerIdCXX │ │ │ ├── a.out │ │ │ └── CMakeCXXCompilerId. cpp │ │ ├── cmake.check_cache │ │ ├── CMakeDirectoryInformation.cmake │ │ ├── CMakeOutput.log │ │ ├── CMakeTmp │ │ ├── feature_tests.bin │ │ ├── feature_tests.c │ │ ├── feature_tests.cxx │ │ ├── Makefile2 │ │ ├── Makefile.cmake │ │ ├── progress.marks │ │ ├── TargetDirectories.txt │ │ └── test_sqrt. dir │ │ ├── build. make │ │ ├── C.includecache │ │ ├── cmake_clean.cmake │ │ ├── DependInfo.cmake │ │ ├── depend.internal │ │ ├── depend. make │ │ ├── flags. make │ │ ├── link.txt │ │ ├── progress. make │ │ └── src │ │ ├── b.c.o │ │ └── main.c.o │ ├── cmake_install.cmake │ ├── Makefile │ └── test_sqrt ├── CMakeLists.txt ├── include │ └── b.h └── src ├── b.c └── main.c
注意在build的目录下生成了一个可执行的文件test_sqrt,运行获取结果如下:
命令: ./test_sqrt 结果: input a: 49.000000 sqrt result: 7.000000
参考文献:
1. Linux Makefile教程: http://blog.csdn.net/liang13664759/article/details/1771246
2. CMake 学习二: http://blog.sina.com.cn/s/blog_53b7ddf00101mjp5.html
3. CMake基本用法: http://blog.sina.com.cn/s/blog_68409a2801019bm7.html
1.gcc是GNU Compiler Collection(就是GNU编译器套件),也可以简单认为是编译器,它可以编译很多种编程语言(括C、C++、Objective-C、Fortran、Java等等)。
2.当你的程序只有一个源文件时,直接就可以用gcc命令编译它。
3.但是当你的程序包含很多个源文件时,用gcc命令逐个去编译时,你就很容易混乱而且工作量大
4.所以出现了make工具
make工具可以看成是一个智能的批处理工具,它本身并没有编译和链接的功能,而是用类似于批处理的方式—通过调用makefile文件中用户指定的命令来进行编译和链接的。
5.makefile是什么?简单的说就像一首歌的乐谱,make工具就像指挥家,指挥家根据乐谱指挥整个乐团怎么样演奏,make工具就根据makefile中的命令进行编译和链接的。
6.makefile命令中就包含了调用gcc(也可以是别的编译器)去编译某个源文件的命令。
7.makefile在一些简单的工程完全可以人工手下,但是当工程非常大的时候,手写makefile也是非常麻烦的,如果换了个平台makefile又要重新修改。
8.这时候就出现了Cmake这个工具,cmake就可以更加简单的生成makefile文件给上面那个make用。当然cmake还有其他功能,就是可以跨平台生成对应平台能用的makefile,你不用再自己去修改了。
9.可是cmake根据什么生成makefile呢?它又要根据一个叫CMakeLists.txt文件(学名:组态档)去生成makefile。
10.到最后CMakeLists.txt文件谁写啊?亲,是你自己手写的。
11.当然如果你用IDE,类似VS这些一般它都能帮你弄好了,你只需要按一下那个三角形
12.cmake是make maker,生成各种可以直接控制编译过程的控制器的配置文件,比如makefile、各种IDE的配置文件。
13.make是一个简单的通过文件时间戳控制自动过程、处理依赖关系的软件,这个自动过程可以是编译一个项目。