我使用C / C ++编写代码,并使用(GNU)Makefile编译代码。我可以使用CMake进行同样的操作并获取MakeFile。但是,使用Makefile和CMake编译代码有什么区别?

#1 楼

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

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

如果您有习惯于Visual Studio的Windows开发人员和Unix开发人员,他们对GNU Make,CMake都非常满意。是一种方法。

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

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

评论


谢谢!只是确认一下,如果我只在Linux环境下编程,而不仅仅是makefile就足够了,但是如果我希望Linux上的程序在Mac上比cmake运行,那是更好的选择,因为据我所知,我们不需要在该文件上创建新的makefile Mac,而是运行cmake。这就是重点吗?

–rish
2014年9月12日上午10:17

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

–Angew不再以SO为荣
2014年9月12日上午10:22

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

– Maxim Egorushkin
2014年9月12日15:17

@Angew非递归是使用完整的项目依赖关系树一次调用make时。与顶级生成文件以特定顺序调用子项目生成文件时的递归相反。

– Maxim Egorushkin
2014-09-12 15:24

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

– ErikAlapää
15/12/23在7:39

#2 楼

关于CMake是“构建生成器”的说法是一个普遍的误解。
从技术上讲这不是错误的;它只是描述了它是如何工作的,而不是它是做什么的。
在问题的上下文中,它们做同样的事情:获取一堆C / C ++文件并将其转换为二进制文件。
所以,真正的区别是什么?


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


CMake执行两步构建:它在ninja中生成低级构建脚本或make或许多其他生成器,然后运行它。通常堆放在Makefile中的所有shell脚本片段仅在生成阶段执行。因此,CMake的构建可以快几个数量级。


CMake的语法比make的语法更容易支持外部工具。


一旦make构建了工件,它就会忘记它是如何构建的。它是由什么来源构建的,哪些编译器标志? CMake跟踪它,make留给您。如果自先前版本的Makefile以来删除了一个库资源,则make不会重建它。


现代CMake(从版本3开始)在以下方面的依赖关系方面起作用:目标”。目标仍然是单个输出文件,但它可以具有可传递(在CMake术语中为“ public” /“ interface”)依赖项。
这些可传递依赖项可以向依赖包公开或隐藏。 CMake将为您管理目录。使用make,您将只能停留在逐个文件和逐个管理目录的级别。


您可以使用中间文件在make中编写一些代码,以弥补最后两个空白,但您自己一个人。 make确实包含图灵完整的语言(偶数为两个,有时三个为数)。前两个太可怕了,实际上几乎没有使用过Guile。
老实说,这就是CMakemake的共同点-它们的语言非常恐怖。想到的是它们:

它们没有用户定义的类型;

CMake具有三种数据类型:字符串,列表和具有属性的目标。 make具有一个:字符串;
您通常通过设置全局变量将参数传递给函数。

这在现代CMake中得到了部分解决-您可以设置目标的属性:set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}");


默认情况下会默认忽略对未定义变量的引用;


评论


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

–解决J
20-2-18在4:01

我不会称其为“完全”错误,但是感谢您的纠正。

– Victor Sergienko
20-2-27在22:56

@VictorSergienko,在OP的问题中没有被问到,但是我正在等待紧急情况……您使用哪种感觉比哪个更好?

–罗伯特·拉格(Robert Lugg)
20 Dec 23 '21:42

我出于历史原因使用make,但我讨厌它。 CMake也不是没有问题(尝试与其交叉编译),但是对于我自己的项目,CMake会成功,因为您编写的代码更少,并且受工具支持。

– Victor Sergienko
20 Dec 24'1:57