Reputation: 5995
I code in C/C++ and use a (GNU) Makefile to compile the code. I can do the same with CMake and get a Makefile. However, what is the difference between using a Makefile and CMake to compile the code?
Upvotes: 550
Views: 304643
Reputation: 1810
As mentioned in the other answers CMake can generate other project files. It refers to these projects as generators.
This lets users write/describe their build using a domain specific language, and use the generator to compile the project. It often results in simpler/better code than writing to these project files directly.
A big advantage is users can use the tool that they are the most comfortable with (Makefiles, Visual Studio, XCode, Ninja, etc). This is nice but arguable introduces complexity. Why not just use Ninja?
The answer is history. (As is the norm in C/C++)
Build systems like Visual Studio have tools that will only accept those project files.
For example Microsoft has a feature called "Static Driver Verifier". A tool to analyze the code of kernel mode windows drivers. However, this tool only works on Visual Studio projects since it works alongside msbuild
.
msbuild /t:sdv /p:Inputs="Parameters" ProjectFile /p:Configuration=configuration /p:Platform=platform
If your build system can't generate Visual Studio project files, then you can't use the tool. This can be a very big deal for some projects/companies.
Upvotes: 3
Reputation: 13475
The statement about CMake being a "build generator" is a common misconception.
It's not technically wrong; it just describes HOW it works, but not WHAT it does.
In the context of the question, they do the same thing: take a bunch of C/C++ files and turn them into a binary.
So, what is the real difference?
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.
You could code up something in make
using intermediate files to cover the last two gaps, but you're on your own. make
does contain a Turing complete language (even two, sometimes three counting Guile); the first two are horrible and the Guile is practically never used.
To be honest, this is what CMake
and make
have in common -- their languages are pretty horrible. Here's what comes to mind:
CMake
has three data types: string, list, and a target with properties. make
has one: string;set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}")
;Upvotes: 156
Reputation: 171097
Make (or rather a Makefile) is a buildsystem - it drives the compiler and other build tools to build your code.
CMake is a generator of buildsystems. It can produce Makefiles, it can produce Ninja build files, it can produce KDEvelop or Xcode projects, it can produce Visual Studio solutions. From the same starting point, the same CMakeLists.txt file. So if you have a platform-independent project, CMake is a way to make it buildsystem-independent as well.
If you have Windows developers used to Visual Studio and Unix developers who swear by GNU Make, CMake is (one of) the way(s) to go.
I would always recommend using CMake (or another buildsystem generator, but CMake is my personal preference) if you intend your project to be multi-platform or widely usable. CMake itself also provides some nice features like dependency detection, library interface management, or integration with CTest, CDash and CPack.
Using a buildsystem generator makes your project more future-proof. Even if you're GNU-Make-only now, what if you later decide to expand to other platforms (be it Windows or something embedded), or just want to use an IDE?
Upvotes: 741