Différence entre l'utilisation de Makefile et CMake pour compiler le code

288

Je code en C / C ++ et utilise un Makefile (GNU) pour compiler le code. Je peux faire la même chose avec CMake et obtenir un MakeFile. Cependant, quelle est la différence entre l'utilisation de Makefile et CMake pour compiler le code?

rish
la source
2
cmake peut également produire des fichiers pour utiliser ninja
BЈовић

Réponses:

403

Make (ou plutôt un Makefile) est un système de build - il pilote le compilateur et d'autres outils de build pour construire votre code.

CMake est un générateur de buildsystems. Il peut produire des Makefiles, il peut produire des fichiers de construction Ninja, il peut produire des projets KDEvelop ou Xcode, il peut produire des solutions Visual Studio. A partir du même point de départ, le même fichier CMakeLists.txt. Donc, si vous avez un projet indépendant de la plate-forme, CMake est également un moyen de le rendre indépendant du système.

Si vous avez des développeurs Windows habitués aux développeurs Visual Studio et Unix qui ne jurent que par GNU Make, CMake est (une des) voie (s) à suivre.

Je recommanderais toujours d'utiliser CMake (ou un autre générateur de buildsystem, mais CMake est ma préférence personnelle) si vous envisagez que votre projet soit multi-plateforme ou largement utilisable. CMake lui-même fournit également de belles fonctionnalités telles que la détection des dépendances, la gestion de l'interface de bibliothèque ou l'intégration avec CTest, CDash et CPack.

L'utilisation d'un générateur de buildsystem rend votre projet plus pérenne. Même si vous êtes GNU-Make-only maintenant, que se passe-t-il si vous décidez plus tard d'étendre à d'autres plates-formes (que ce soit Windows ou quelque chose d'incorporé), ou si vous voulez simplement utiliser un IDE?

Angew n'est plus fier de SO
la source
5
@rish Oui, c'est l'essentiel. Notez cependant qu'il existe plus de façons de programmer sur Linux que Makefiles - voir par exemple QtCreator, KDEvelop, Ninja. Pour chacun d'eux, il s'agit soit de «créer un projet et de le garder synchronisé avec le Makefile», soit de «réexécuter CMake». Et, comme le mentionne la réponse, CMake a également d'autres fonctionnalités, comme la découverte de dépendances (par exemple find_package()) ou le support de test / packaging.
Angew n'est plus fier de SO le
3
J'ai lu que CMake ne peut pas créer de makefiles non récursifs. Est-ce toujours vrai?
Maxim Egorushkin,
1
@Angew Non récursif, c'est quand make est invoqué une fois avec l'arborescence complète des dépendances du projet. Par opposition à récursif lorsqu'un makefile de niveau supérieur appelle des makefiles de sous-projet dans un certain ordre.
Maxim Egorushkin,
3
C'est une faiblesse importante de CMake - GNU make a ses rides, mais si vous prenez le temps de l'apprendre, il est extrêmement puissant et polyvalent, et fonctionne sur une énorme quantité de plates-formes. Ne pas avoir d'arbre de dépendance complet à analyser est une faille majeure, il suffit de google pour «rendre récursif considéré comme nuisible».
Erik Alapää
1
@ ErikAlapää Je vais lire l'article en détail, mais à première vue - ils semblent parler de marque récursive où la profondeur de récursivité est basée sur les données (c'est-à-dire dépend de la profondeur du répertoire source, etc.). Ce n'est pas le cas avec CMake: la profondeur totale des appels make est toujours de 3, quelle que soit la structure du projet. Il est juste que certains bits sont déléguées à un submakefile au lieu de tout en un, mais il ne pas refléter la structure du projet de quelque façon. De plus, les sous-fichiers ne sont pas vraiment "autonomes", donc ils ne souffrent pas du problème de dépendance excessive / insuffisante.
Angew n'est plus fier de SO
39

La déclaration selon laquelle CMake est un «générateur de génération» est une idée fausse courante.

Ce n'est pas techniquement mauvais; il décrit simplement COMMENT cela fonctionne, mais pas CE QU'IL fait.

Dans le contexte de la question, ils font la même chose: prendre un tas de fichiers C / C ++ et les transformer en binaire.

Alors, quelle est la vraie différence?

  • CMake est beaucoup plus haut niveau. Il est conçu pour compiler C ++, pour lequel vous écrivez beaucoup moins de code de construction, mais peut également être utilisé pour une construction à usage général. makea également des règles C / C ++ intégrées, mais elles sont pour la plupart inutiles.

  • CMakefait une construction en deux étapes: il génère un script de construction à faible niveau ninjaou makeou bien d' autres générateurs, puis l' exécuter. Tous les éléments de script shell qui sont normalement empilés Makefilene sont exécutés qu'au stade de la génération. Ainsi, la CMakeconstruction peut être plus rapide de plusieurs ordres de grandeur.

  • La grammaire de CMakeest beaucoup plus facile à prendre en charge pour les outils externes que pour make .

  • Une fois makeconstruit un artefact, il oublie comment il a été construit. À partir de quelles sources il a été construit, quels drapeaux de compilation? CMakele suit, vous le makelaisse. Si l'une des sources de bibliothèque a été supprimée depuis la version précédente de Makefile, makene la reconstruira pas.

  • Modern CMake(à partir de la version 3) fonctionne en termes de dépendances entre "cibles". Une cible est toujours un seul fichier de sortie (malheureusement), mais peut avoir des dépendances transitives ("public" / "interface" en termes de CMake). Ces dépendances transitives peuvent être exposées ou masquées aux packages dépendants. CMakegérera également les répertoires pour vous. Avec make, vous êtes coincé au niveau fichier par fichier et gérer les répertoires à la main.

Vous pouvez coder quelque chose en makeutilisant des fichiers d'indicateur pour combler les deux dernières lacunes, mais vous êtes seul. makecontient un langage complet de Turing (même deux, parfois trois comptant Guile ), et tous sont horribles.

Pour être honnête, c'est ce que CMakeet makeont en commun - leurs langues sont assez horrible:

  • Ils n'ont pas de types;
  • pas de tableaux, seulement des chaînes séparées par des espaces, échappant ainsi à l'enfer;
  • vous passez normalement des arguments aux fonctions en définissant des variables globales; (ceci est abordé dans CMake moderne - les variables peuvent avoir des espaces de noms maintenant; une cible est un espace de noms pour ses propriétés)
  • faire référence à une variable non définie est silencieusement ignoré par défaut;

commencer avec.

Mais CMakevous écrivez beaucoup moins de lignes de code.

Victor Sergienko
la source
1
Quelques bonnes informations ici, mais une remarque est complètement fausse: cmake a un type LIST car avec les fonctions LIST appropriées, ce qui est crucial pour de nombreuses tâches de build-système, une petite différence: cmake.org/cmake/help/git-master/command /list.html
resolutionJ
Je ne dirais pas que c'est "complètement" faux, mais merci pour la correction.
Victor Sergienko