CMake的原理与使用方法

一.为什么需要CMake,什么是CMake

   1.由于各种make工具遵循不同的规范和标准,所执行的Makefile格式也不同,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等。这些 Make 工具遵循着不同的规范和标准,所执行的 Makefile 格式也千差万别。

这样就带来了一个严峻的问题:如果软件想跨平台,必须要保证能够在不同平台编译。而如果使用上面的 Make 工具,就得为每一种标准写一次 Makefile ,这将是一件让人抓狂的工作。

CMake 就是针对上面问题所设计的工具:它首先允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程,然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。显然,CMake 是一个比上述几种 make 更高级的编译配置工具。让软件真正实现了跨平台。

一些使用 CMake 作为项目架构系统的知名开源项目有 VTK、ITK、KDE、OpenCV、OSG 等 。

   

2.官方文档网址:www.cmake.org

3.CMake的主要特点

跨平台:CMake可以在多种操作系统上运行,包括Windows、Linux、macOS等。

编译器无关:CMake支持多种编译器,如GCC、Clang、Microsoft Visual C++等。

自动化:CMake可以自动检测系统特性,如库、头文件和编译器特性,并根据这些信息生成构建文件。

可扩展性:CMake提供了模块和脚本机制,允许用户扩展其功能。

生成多种构建系统:CMake可以生成多种构建系统的构建文件,如Makefile、Ninja、Visual Studio工程文件等。

开发语言:CMake的开发语言是C和C++。

4.其他构建工具     

除了CMake外还有很多其他构建工具:XMake,qmake,Scons, Ninja, Meson, Baze等

二.CMake怎么用

1.CMake与makefile关系图

2.CMake处理原理

CMake有两个主要的阶段。首先是"配置(configure)",在此阶段CMake处理所有的输入然后创建软件构建过程的内部表达。第二个阶段是"生成(generate)",负责创建出实际的构建文件。

1环境变量与缓存

对1999年甚至是今天的许多构建系统来说,生成工程时都要用到底层(shell级别)的环境变量。典型的情况是,用PROJECT_ROOT环境变量来指向源码树的根目录。环境变量还被用于指定可选软件包和外部软件包。但是使用环境变量的方法也有弊端,它需要每次构建时都重新设置环境变量。为解决这个问题,CMake使用缓存文件来存储生成过程中用到的所有变量。这些变量不再是环境变量,而是CMake变量。CMake针对某个特定构建树第一次运行时,会创建一个CMakeCache.txt文件,存储当前构建过程中需要用到的CMake变量。这个缓存文件属于构建树的一部分,所以在之后的每次针对该构建树的重新配置时, 这些变量都是可重用的。

2配置阶段

在配置阶段,CMake首先尝试读取CMakeCache.txt文件,该文件在第一次运行时生成。然后,读取源码树根目录下的CMakeLists.txt文件,并使用CMake词法分析器处理。CMakeLists.txt中的每条命令都由一个命令模式对象执行。通过include和add_subdirectory命令,更多的CMakeLists.txt得到执行。对于每条命令,CMake都有一个C++对象来处理,比如add_library, if, add_executable, add_subdirectory,include等。实际上,整个CMake语言就是以命令调用的方式实现的。词法分析器只不过将输入文件内容转化为命令和命令参数而已。

配置阶段主要是运行用户定义的CMake代码。等到执行完之后,以及所有缓存变量计算完成之后,CMake在内存中得到一个项目构建的内部表达。这个内存中的内部表达包括了所有的库文件,可执行文件,定制的命令,以及生成指定generator(指特定的编译环境)所需的其他必要信息。这时,CMakeCache.txt会被存储到磁盘上,供以后重新运行CMake时使用。

项目在内存中的表达实际上是一些待生成的目标的集合,包括基本的库文件和可执行文件。CMake还支持目标的定制,即用户可以定义输入和输出,并提供定制的可在构建过程中运行的可执行文件或脚本。CMake将每个目标存储在一个cmTarget对象中,然后多个cmTarget存储在一个cmMakefile对象中,cmMakefile对象实际上用来存储源码树中某个目录中的所有目标。最后得到的结果是一棵cmMakefile对象的树,树结点中存储cmTarget对象的映射。

3生成阶段

一旦配置(configure)阶段完成,生成(generator)阶段就可以开始了。生成阶段将生成用户指定类型(如Visual Studio或GNU/Linux GCC)的构建文件。这时,目标的内部表达(库,可执行文件,定制目标)转化为本地构建工具的输入文件,如Visual Studio或Makefile文件。CMake由配置阶段获得的内部表达要尽可能地抽象和通用,这样的数据结构才能被不同的本地构建工具所共享。

3.安装cmake

sudo apt-get install cmake

4.构建工程项目流程

(1).构建CMakeLists.txt

CMake 构建脚本是一个纯文本文件,您必须将其命名为 CMakeLists.txt,并在其中包含 CMake 构建您的 C/C++ 库时需要使用的命令。如果您的原生源代码文件还没有 CMake 构建脚本,您需要自行创建一个,并在其中包含适当的 CMake 命令。

(2).在包含CMakeLists.txt的目录下使用cmake

         1)构建放在当前目录下(内部构建):cmake . 即在当前目录cmake,在当前目录build。

         2)在当前目录下创建build文件夹存放构建文件(外部构建),build内输入cmake ..。即在上级目录cmake,在该目录下build。

结果:生成4个东西:CMakeFiles文件夹、cmake_install.cmake、CMakeCache.txt、Makefile

只要产生Makefile文件,就说明cmake成功了

(3).在包含Makefile的目录下使用make

直接在build出4个东西的目录下(命令针对的是Makefile)输入make

(4).生成可执行文件。 输入./文件名运行

5.举例

1)先编写main.cpp

#include <iostream>

using namespace std;

int main(){

cout<<"hello,world"<<endl;

return 0;

}

2)编写CMakeLists.txt

PROJECT(HELLO)            #工程名为HEELO

SET(SRC_LIST main.cpp)    #变量SRC_LIST包含main.cpp

MESSAGE(STATUS "This is BINARY dir " ${HELLO_BINARY_DIR})

MESSAGE(STATUS "This is SOURCE dir " ${HELLO_SOURCE_DIR})

ADD_EXECUTABLE(hello ${SRC_LIST}) #生成可执行程序文件名为hello,源文件读取变量SRC_LIST中内容

3)cmake

cmake .

生成了4个东西:CMakeFiles文件夹、cmake_install.cmake、CMakeCache.txt、Makefile

4)make

make

生成了可执行文件hello

5)执行

./hello

显示"hello,world"

三.如何编写CMakeLists.txt

1.CMakeLists.txt并不是顺序执行的,相当于一系列的声明

CMakeList.txt 的语法比较简单,由命令、注释和空格组成:

#后面内容为注释;

命令由命令名称、小括号和参数组成,参数之间使用空格进行间隔,其中命令是不区分大小写的。

2.语法详解

PROJECT关键字 ※

可以用来指定工程的名字和支持的语言,默认支持所有语言

PROJECT(HELLO) 指定了工程的名字为HELLO,且支持所有语言(建议这样做)

PROJECT(HELLO CXX)指定了工程的名字为HELLO,仅支持C++语言

PROJECT(HELLO C CXX)指定了工程的名字为HELLO,仅支持C和C++语言

该指定隐式地定义了两个CMake变了

<projectname>_BINARY_DIR

<projectname>_SOURCE_DIR

本例中是HELLO_BINARY_DIR、HELLO_SOURCE_DIR

MESSAGE关键字就可以直接使用这两个变量。当前都指向当前的工作目录

SET关键字

SET用来显式的指定变量,可以为多个

SET(SRC_LIST main.cpp) 意为SRC_LIST变量包含了main.cpp

SET(SRC_LIST main.cpp test1.cpp test2.cpp) 意为SRC_LIST变量包含了main.cpp、test1.cpp、test2.cpp

MESSAGE关键字

向终端输出用户自定义的信息,主要包含三种:

SEND_ERROR:产生错误,生成过程被跳过

STATUS:输出前缀为- -的信息

FATAL_ERROR:立即终止所有cmake过程

ADD_EXECUTABLE关键字 ※

生成可执行文件

ADD_EXECUTABLE(hello $(SRC_LIST)),生成的可执行文件名为hello,源文件读取变量SRC_LIST中的内容

也可直接写为 ADD_EXECUTABLE(hello main.cpp)

注意:工程名的HELLO和生成的可执行文件hello是没有任何关系的

所以,上例中的5行CMakeLists.txt可以简化为2行:

PROJECT(HELLO)

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY关键字

①有子目录时,要用ADD_SUBDIRECTORY关键字包含所有需要访问的子文件夹。除了工程目录外,每个被访问的子目录里也都需要有一个CMakeLists.txt说明

②将目标文件放入构建目录的bin子目录:ADD_SUBDIRECTOR(子目录名 bin):自动在子目录下新建一个名为bin的子目录,存放中间二进制文件、目标二进制文件、库文件。

注意:文件就是file。目录(文件夹)就是directory。

语法基本原则

(1).变量取值 ${ }

(1).分隔多个文件:空格或者分号

(3).大小写:指令大小写不敏感,参数和变量对大小写敏感

3.安装文件

INSTALL(FILES 文件名 DESTINATION 目标地址)

举例3:

工程目录下的CMakeLists.txt添加一行:

INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake)   #会自动安装到/usr/local/share/doc/cmake下

DESTINATION后面:

(1).写绝对路径

(2).相对路径:

CMAKE_INSTALL_PREFIX 默认是在/usr/local/

若想要更改,可以手动设置

set(CMAKE_INSTALL_PREFIX "目标路径")

这时候再 DESTINATION ${CMAKE_INSTALL_PREFIX},就导出到目标路径上了。

4.可执行文件安装

在src的CMakeLists.txt里输入

INSTALL(TARGETS hello DESTINATION bin)

5.生成静态库和动态库

SET(变量 源文件名)

ADD_LIBRARY(库名 STATIC或SHARED ${变量})

构建动态库(命令用SHARED) (构建静态库,命令用STATIC)

举例:

SET(LIBHELLO_SRC hello.cpp)

ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})    #生成动态库libhello.so

6.使用外部头文件和共享库

 (1)添加头文件搜索路径:

  INCLUDE_DIRECTORIES(路径)

 (2)添加需要链接的共享库

TARGET_LINK_LIBRARIES(源文件名 库名)

TARGET_LINK_LIBRARIES(main libhello.so)    #链接动态库

TARGET_LINK_LIBRARIES(main libhello.a)     #链接静态库

四.QT中的CMake

1.QMake和CMake

  qmake和cmake两者都用来构建系统,都生成一个Makefile,该文件由make读取以构建项目,告诉编译器和链接器该做什么,以创建可执行文件(或动态或静态库)。

  qmake专注于使用Qt的项目,QtCreator可以轻松生成项目文件(适合初学者),并由QtCreator支持;CMake用于广泛的项目,支持多种平台和语言,受多个IDE支持:例如QtCreator,Visual Studio,

  生成多个IDE的项目描述,包含简化Qt使用的命令(最重要:automoc)。如果项目使用Qt,则最好使用qmake。 CMake更通用,几乎适合任何类型的项目。

2.Qt公司自Qt 5.14版本开始推荐使用CMake作为Qt项目的构建系统,而不是qmake。

  CMake是一个跨平台的构建系统,支持多种编译器和IDE,而qmake是Qt自带的构建工具,主要用于Qt项目。

Qt公司推荐使用CMake的原因包括:

跨平台支持:CMake支持多种操作系统和编译器,使得Qt项目可以在不同的平台上轻松构建。

社区支持:CMake拥有一个活跃的社区,提供了大量的模块和工具,可以帮助开发者更高效地构建和管理项目。

集成支持:CMake与许多IDE和构建系统紧密集成,如Visual Studio、Xcode、Make等。

模块化:CMake提供了模块化的构建脚本,使得项目可以更容易地管理和扩展。

性能:CMake的配置和生成过程通常比qmake更快,特别是在处理大型项目时。

3.qmake更适合构建小型Qt项目,简单易用;而cmake更适合构建复杂、跨平台的C++项目,功能更加强大和灵活。

如果没有什么跨平台需求的话,qmake也是没有问题的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI+程序员在路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值