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


当前回答

关于CMake是“构建生成器”的说法是一种常见的误解。

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

在这个问题的上下文中,他们做了同样的事情:取一堆C/ c++文件并将它们转换为二进制文件。

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

CMake is much more high-level. It's tailored to compile C++, for which you write much less build code, but can be also used for general purpose build. make has some built-in C/C++ rules as well, but they are useless at best. CMake does a two-step build: it generates a low-level build script in ninja or make or many other generators, and then you run it. All the shell script pieces that are normally piled into Makefile are only executed at the generation stage. Thus, CMake build can be orders of magnitude faster. The grammar of CMake is much easier to support for external tools than make's. Once make builds an artifact, it forgets how it was built. What sources it was built from, what compiler flags? CMake tracks it, make leaves it up to you. If one of library sources was removed since the previous version of Makefile, make won't rebuild it. Modern CMake (starting with version 3.something) works in terms of dependencies between "targets". A target is still a single output file, but it can have transitive ("public"/"interface" in CMake terms) dependencies. These transitive dependencies can be exposed to or hidden from the dependent packages. CMake will manage directories for you. With make, you're stuck on a file-by-file and manage-directories-by-hand level.

您可以在make中编写一些代码,使用中间文件来弥补最后两个空白,但这只能靠您自己了。make确实包含一个图灵完备语言(甚至两个,有时三个算上Guile);前两个是可怕的,Guile几乎从未使用过。

老实说,这就是CMake和make的共同之处——它们的语言都很糟糕。我想到的是:

它们没有用户定义的类型; CMake有三种数据类型:字符串、列表和带有属性的目标。使有一:串; 通常通过设置全局变量将参数传递给函数。 这在现代CMake中得到了部分解决——你可以设置一个目标的属性:set_property(target helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"); 默认情况下,引用未定义的变量会被静默忽略;

其他回答

正如在其他答案中提到的,CMake可以生成其他项目文件。它将这些项目称为生成器。

这允许用户使用特定于领域的语言编写/描述他们的构建,并使用生成器编译项目。与直接写入这些项目文件相比,它通常会产生更简单/更好的代码。

最大的优势是用户可以使用他们最熟悉的工具(Makefiles, Visual Studio, XCode, Ninja等)。这很好,但有争议会带来复杂性。为什么不直接使用Ninja?

答案是历史。(这是C/ c++的标准)

像Visual Studio这样的构建系统拥有只接受这些项目文件的工具。

例如,微软有一个叫做“静态驱动程序验证器”的功能。一个分析内核模式windows驱动程序代码的工具。但是,这个工具只适用于Visual Studio项目,因为它与msbuild一起工作。

msbuild /t:sdv /p:Inputs="Parameters" ProjectFile /p:Configuration=configuration /p:Platform=platform

如果您的构建系统不能生成Visual Studio项目文件,那么您就不能使用该工具。对于一些项目/公司来说,这是一件非常重要的事情。

关于CMake是“构建生成器”的说法是一种常见的误解。

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

在这个问题的上下文中,他们做了同样的事情:取一堆C/ c++文件并将它们转换为二进制文件。

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

CMake is much more high-level. It's tailored to compile C++, for which you write much less build code, but can be also used for general purpose build. make has some built-in C/C++ rules as well, but they are useless at best. CMake does a two-step build: it generates a low-level build script in ninja or make or many other generators, and then you run it. All the shell script pieces that are normally piled into Makefile are only executed at the generation stage. Thus, CMake build can be orders of magnitude faster. The grammar of CMake is much easier to support for external tools than make's. Once make builds an artifact, it forgets how it was built. What sources it was built from, what compiler flags? CMake tracks it, make leaves it up to you. If one of library sources was removed since the previous version of Makefile, make won't rebuild it. Modern CMake (starting with version 3.something) works in terms of dependencies between "targets". A target is still a single output file, but it can have transitive ("public"/"interface" in CMake terms) dependencies. These transitive dependencies can be exposed to or hidden from the dependent packages. CMake will manage directories for you. With make, you're stuck on a file-by-file and manage-directories-by-hand level.

您可以在make中编写一些代码,使用中间文件来弥补最后两个空白,但这只能靠您自己了。make确实包含一个图灵完备语言(甚至两个,有时三个算上Guile);前两个是可怕的,Guile几乎从未使用过。

老实说,这就是CMake和make的共同之处——它们的语言都很糟糕。我想到的是:

它们没有用户定义的类型; CMake有三种数据类型:字符串、列表和带有属性的目标。使有一:串; 通常通过设置全局变量将参数传递给函数。 这在现代CMake中得到了部分解决——你可以设置一个目标的属性:set_property(target helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}"); 默认情况下,引用未定义的变量会被静默忽略;

Make(或者更确切地说是Makefile)是一个构建系统——它驱动编译器和其他构建工具来构建代码。

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

如果你有使用Visual Studio的Windows开发人员和使用GNU Make的Unix开发人员,CMake是你可以选择的方法之一。

如果你希望你的项目是多平台或广泛使用的,我总是推荐使用CMake(或其他构建系统生成器,但CMake是我个人的偏好)。CMake本身也提供了一些不错的特性,比如依赖检测、库接口管理,或者与CTest、ccdash和CPack的集成。

使用构建系统生成器使您的项目更加经得起考验。即使您现在只使用gnu - make,但如果稍后决定扩展到其他平台(无论是Windows还是嵌入式平台),或者只想使用IDE,该怎么办?