386

I code on 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 Makefile and CMake to compile the code?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
rish
  • 4,307
  • 5
  • 20
  • 24

2 Answers2

520

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?

Iulian Onofrei
  • 7,489
  • 8
  • 59
  • 96
Angew is no longer proud of SO
  • 156,801
  • 13
  • 318
  • 412
  • 2
    thank you! Just to confirm, that if I only program on Linux environment than only makefile is adequate but if I want the program from Linux to run in Mac than cmake is better option as I understand that, we don't need to make a new makefile on the Mac but rather just run the cmake. Is that the whole point? – rish Sep 12 '14 at 10:17
  • 5
    @rish Yes, that's the gist. Note however, that there's more ways to program on Linux than Makefiles - see e.g. QtCreator, KDEvelop, Ninja. For each of these, it's either "create a project and keep it in sync with the Makefile," or "re-run CMake." And, as the answer mentions, CMake has other functionality too, like dependency discovery (e.g. [`find_package()`](http://www.cmake.org/cmake/help/v3.0/command/find_package.html)) or testing/packaging support. – Angew is no longer proud of SO Sep 12 '14 at 10:22
  • 3
    I read that CMake cannot create non-recursive makefiles. Is that still true? – Maxim Egorushkin Sep 12 '14 at 15:17
  • @MaximYegorushkin What exactly do you mean with "recursive" or "non-recursive" makefiles? Makefiles generated by CMake have a well-defined 3-level hierarchy without loops back up, if that's what you're after. – Angew is no longer proud of SO Sep 12 '14 at 15:18
  • 1
    @Angew _Non-recursive_ is when make is invoked once with complete project dependency tree. As opposed to _recursive_ when a top level makefile invokes sub-project makefiles in certain order. – Maxim Egorushkin Sep 12 '14 at 15:24
  • @MaximYegorushkin OK; by this definition, it creates recursive makefiles. – Angew is no longer proud of SO Sep 12 '14 at 15:26
  • 3
    This is an important weakness of CMake - GNU make has its wrinkles, but if you take the time to learn it, it is extremely powerful and versatile, and works on an enormous amount of platforms. Not having a complete dependency tree to analyze is a major flaw, just google for 'recursive make considered harmful'. – Erik Alapää Dec 23 '15 at 07:39
  • 1
    @ErikAlapää I will read the article in detail, but from a first glance - they seem to be talking about recursive make where the depth of recursion is data-driven (i.e. depends on source directory depth etc.). That's not the case with CMake: the total depth of make invocations is always 3, regardless of project structure. It's just that some bits are delegated to a submakefile instead of all in one, but it does *not* reflect project structure in any way. Plus, the submakefiles are not really "self-contained", so they don't suffer the over/under dependency problem. – Angew is no longer proud of SO Dec 23 '15 at 09:57
  • @Angew If make is invoked on a sub-makefile instead of including into main makefile, then, by definition, make will only see part of the dependency tree. – Erik Alapää Dec 24 '15 at 09:17
  • 1
    @ErikAlapää The recursivity of generated makefiles, and the rationale for it, is also handled in [CMake's official wiki](https://cmake.org/Wiki/CMake_FAQ#Why_does_CMake_generate_recursive_Makefiles.3F). – Angew is no longer proud of SO Jun 07 '17 at 09:02
  • 1
    This post [CMake vs Make](https://prateekvjoshi.com/2014/02/01/cmake-vs-make/) explains more. So it's more reasonable to compare CMake with [Autotools](https://en.wikipedia.org/wiki/GNU_Build_System), `configure` and `make`. – where23 Jun 22 '17 at 03:21
83

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:

  • They have no user-defined types;
  • CMake has three data types: string, list, and a target with properties. make has one: string;
  • you normally pass arguments to functions by setting global variables.
    • This is partially dealt with in modern CMake - you can set a target's properties: set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}");
  • referring to an undefined variable is silently ignored by default;
Victor Sergienko
  • 11,714
  • 2
  • 50
  • 78
  • 2
    Some good information here, but one remark is completely wrong: cmake has a LIST type since with proper LIST functions which is crucial for lots of build-system tasks, a bit difference: https://cmake.org/cmake/help/git-master/command/list.html – solvingJ Feb 18 '20 at 04:01
  • 1
    I wouldn't call it "completely" wrong, but thanks for correction. – Victor Sergienko Feb 27 '20 at 22:56
  • @VictorSergienko, Not asked in the OP's question, but I was waiting for the punch line...What do you use which you feel is better than either? – Robert Lugg Dec 23 '20 at 21:42
  • I use make for historical reasons, and I hate it. CMake is not without problems too (try cross compiling with it), but for my own projects CMake would win because you write fewer code, and it’s supported by tools. – Victor Sergienko Dec 24 '20 at 01:57