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 的集成。
使用构建系统生成器使您的项目更具前瞻性。即使您现在只使用 GNU-Make,如果您以后决定扩展到其他平台(无论是 Windows 还是嵌入式),或者只是想使用 IDE 怎么办?
关于 CMake 是“构建生成器”的说法是一个常见的误解。
这在技术上并没有错。它只是描述了它是如何工作的,而不是它的作用。
在问题的上下文中,他们做同样的事情:获取一堆 C/C++ 文件并将它们转换为二进制文件。
那么,真正的区别是什么?
CMake 更高级。它专为编译 C++ 而定制,您为此编写的构建代码要少得多,但也可用于通用构建。 make 也有一些内置的 C/C++ 规则,但它们充其量是无用的。
CMake 进行两步构建:它在 ninja 或 make 或许多其他生成器中生成低级构建脚本,然后运行它。通常堆积到 Makefile 中的所有 shell 脚本片段仅在生成阶段执行。因此,CMake 构建速度可以快几个数量级。
CMake 的语法比 make 更容易支持外部工具。
一旦 make 构建了一个工件,它就会忘记它是如何构建的。它是从什么来源构建的,什么编译器标志? CMake 跟踪它,让它由你决定。如果自上一版本的 Makefile 以来删除了其中一个库源,make 将不会重建它。
现代 CMake(从版本 3.something 开始)根据“目标”之间的依赖关系工作。目标仍然是单个输出文件,但它可以具有传递(CMake 术语中的“公共”/“接口”)依赖关系。这些传递依赖可以暴露给依赖包,也可以隐藏在依赖包中。 CMake 将为您管理目录。使用 make,您会被困在逐个文件和手动管理目录的级别。
您可以使用中间文件在 make
中编写代码来弥补最后两个空白,但您只能靠自己。 make
确实包含一个 Turing complete language(即使是两个,有时也包含三个 Guile);前两个太可怕了,Guile 实际上从未使用过。
老实说,这就是 CMake
和 make
的共同点——他们的语言非常糟糕。这就是我想到的:
它们没有用户定义的类型;
CMake 具有三种数据类型:字符串、列表和具有属性的目标。 make 有一个:字符串;
您通常通过设置全局变量将参数传递给函数。这在现代 CMake 中得到了部分处理 - 您可以设置目标的属性: set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}");
这在现代 CMake 中得到了部分处理 - 您可以设置目标的属性: set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}");
默认情况下,对未定义变量的引用会被忽略;
find_package()
)或测试/打包支持。