使用Makefile和CMake编译代码之间的区别


288

我使用C / C ++编写代码,并使用(GNU)Makefile编译代码。我可以用CMake做同样的事情,得到一个MakeFile。但是,使用Makefile和CMake编译代码有什么区别?


2
cmake的也可以产生文件,使用忍者
BЈовић

Answers:


402

Make(或一个Makefile)是一个构建系统-它驱动编译器和其他构建工具来构建代码。

CMake是构建系统的生成器。它可以产生Makefile,可以产生Ninja构建文件,可以产生KDEvelop或Xcode项目,可以产生Visual Studio解决方案。从相同的起点,相同的CMakeLists.txt文件。因此,如果您有一个与平台无关的项目,那么CMake也是使其与系统无关的一种方式。

如果您有习惯于Visual Studio的Windows开发人员和GNU Make誓言的Unix开发人员,那么CMake是(一种或多种)选择。

如果您打算使项目成为多平台或广泛使用的项目,我总是建议使用CMake(或其他构建系统生成器,但CMake是我个人的喜好)。CMake本身还提供了一些不错的功能,例如依赖关系检测,库接口管理或与CTest,CDash和CPack的集成。

使用buildsystem生成器可使您的项目更具前瞻性。即使您现在仅使用GNU-Make,如果以后决定扩展到其他平台(Windows或嵌入式的平台),或者只是想使用IDE怎么办?


5
@rish是的,这就是要点。但是请注意,在Linux上有比Makefiles更多的编程方法-例如参见QtCreator,KDEvelop,Ninja。对于其中每一个,它要么是“创建一个项目并使它与Makefile保持同步”,要么是“重新运行CMake”。并且,正如答案所提到的,CMake也具有其他功能,例如依赖关系发现(例如find_package())或测试/打包支持。
Angew不再为2014年

3
我读到CMake无法创建非递归的makefile。还是这样吗?
Maxim Egorushkin 2014年

1
@Angew 非递归是使用完整的项目依赖树调用一次make时。与顶级makefile以特定顺序调用子项目makefile时的递归相反。
Maxim Egorushkin 2014年

3
这是CMake的一个重要弱点-GNU make会产生皱纹,但是如果您花时间学习它,它会非常强大且用途广泛,并且可以在大量平台上运行。没有完整的依赖关系树来分析是一个主要缺陷,只是google认为“递归使有害”。
ErikAlapää2015年

1
@ErikAlapää我将详细阅读该文章,但乍一看-他们似乎是在谈论递归make,其中递归的深度是数据驱动的(即取决于源目录的深度等)。CMake并非如此:无论项目结构如何,make调用的总深度始终为3。只是有些位委托给了一个子makefile,而不是全部委托给一个子makefile,但是它并不能以任何方式反映项目的结构。此外,子makefile文件并不是真正的“自包含”文件,因此它们不会遭受过度/欠缺依赖性问题。
Angew不再为2015年

38

关于CMake是“构建生成器”的说法是一个普遍的误解。

从技术上讲这没有错;它只是描述了它如何工作,而不是它做什么。

在问题的上下文中,它们执行相同的操作:提取一堆C / C ++文件并将其转换为二进制文件。

那么,真正的区别是什么?

  • CMake更高级。它专为编译C ++而设计,您可以为其编写更少的构建代码,但也可以用于通用构建。make也有一些内置的C / C ++规则,但是它们几乎没有用。

  • CMake做了两个步骤构建:它生成一个低级别的构建脚本ninjamake或许多其他发电机,然后运行它。通常堆入的所有Shell脚本片段Makefile仅在生成阶段执行。因此,CMake构建可以快几个数量级。

  • CMake支持语法的语法比make的语法容易得多

  • 一旦make构建了工件,它就会忘记它是如何构建的。它的来源是什么,编译器有哪些标志?CMake跟踪它,make将它留给您。如果自的早期版本起删除了一个库源Makefilemake则不会重建它。

  • Modern CMake(从版本3.something开始)根据“目标”之间的依赖关系工作。目标(仍然)仍然是单个otput文件,但可以具有传递(CMake术语为“ public” /“ interface”)依赖性。这些可传递依赖项可以从依赖包中公开或隐藏。CMake也会为您管理目录。使用make,您将停留在逐个文件和逐个管理目录的级别。

您可以make使用标志文件来弥补最后两个空白,从而编写一些代码,但您自己一个人。make确实包含图灵完整的语言(偶数为两种,有时甚至数为Guile则为三),而且它们都太可怕了。

说实话,这是什么CMake,并make有共同的-他们的语言是相当可怕:

  • 它们没有类型。
  • 没有数组,只有空格分隔的字符串,从而逃脱了地狱;
  • 您通常通过设置全局变量将参数传递给函数;(这在现代CMake中正在解决-变量现在可以具有名称空间;目标是其属性的名称空间)
  • 默认情况下,对未定义变量的引用将被静默忽略;

首先。

但是,CMake您只需编写更少的代码行。


1
这里有一些很好的信息,但是有一个说法是完全错误的:cmake具有LIST类型,因为它具有适当的LIST函数,这对于许多构建系统任务至关重要,这有点不同:cmake.org/cmake/help/git-master/command /list.html
resolveJ

我不会称其为“完全”错误,但是感谢您的纠正。
维克多·谢尔坚科
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.