Was ist der Unterschied zwischen der Verwendung eines Makefiles und CMake zum Kompilieren des Codes?

Lesezeit: 6 Minuten

Benutzeravatar von rish
rish

Ich programmiere in C/C++ und benutze ein (GNU) Makefile, um den Code zu kompilieren. Ich kann das gleiche mit CMake machen und ein Makefile bekommen. Was ist jedoch der Unterschied zwischen der Verwendung eines Makefiles und CMake zum Kompilieren des Codes?

Angew ist nicht mehr stolz auf den User-Avatar von SO
Angew ist nicht mehr stolz auf SO

Make (oder eher ein Makefile) ist ein Buildsystem – es steuert den Compiler und andere Build-Tools, um Ihren Code zu erstellen.

CMake ist ein Generator von Buildsystemen. Es kann Makefiles produzieren, es kann Ninja-Build-Dateien produzieren, es kann KDEvelop- oder Xcode-Projekte produzieren, es kann Visual Studio-Lösungen produzieren. Vom gleichen Ausgangspunkt, der gleichen CMakeLists.txt-Datei. Wenn Sie also ein plattformunabhängiges Projekt haben, ist CMake eine Möglichkeit, es auch Buildsystem-unabhängig zu machen.

Wenn Sie Windows-Entwickler haben, die an Visual Studio und Unix-Entwickler gewöhnt sind, die auf GNU Make schwören, ist CMake (einer) der richtige Weg.

Ich würde immer empfehlen, CMake (oder einen anderen Buildsystem-Generator, aber CMake ist meine persönliche Präferenz) zu verwenden, wenn Sie beabsichtigen, dass Ihr Projekt plattformübergreifend oder allgemein verwendbar ist. CMake selbst bietet auch einige nette Funktionen wie Abhängigkeitserkennung, Verwaltung von Bibliotheksschnittstellen oder Integration mit CTest, CDash und CPack.

Die Verwendung eines Buildsystem-Generators macht Ihr Projekt zukunftssicherer. Selbst wenn Sie jetzt nur GNU-Make verwenden, was ist, wenn Sie sich später entscheiden, auf andere Plattformen zu erweitern (sei es Windows oder etwas Embedded) oder einfach nur eine IDE verwenden möchten?

  • Danke! Nur um zu bestätigen, dass, wenn ich nur in einer Linux-Umgebung programmiere, nur Makefile ausreichend ist, aber wenn ich möchte, dass das Programm von Linux auf Mac läuft, ist cmake die bessere Option, da ich das verstehe, müssen wir kein neues Makefile erstellen der Mac sondern einfach nur den cmake ausführen. Ist das der springende Punkt?

    – rish

    12. September 2014 um 10:17 Uhr

  • @rish Ja, das ist das Wesentliche. Beachten Sie jedoch, dass es unter Linux mehr Möglichkeiten zum Programmieren gibt als Makefiles – siehe zB QtCreator, KDEvelop, Ninja. Für jede davon heißt es entweder „ein Projekt erstellen und mit dem Makefile synchron halten“ oder „CMake erneut ausführen“. Und wie in der Antwort erwähnt, hat CMake auch andere Funktionen, wie die Erkennung von Abhängigkeiten (z find_package()) oder Unterstützung beim Testen/Verpacken.

    – Angew ist nicht mehr stolz auf SO

    12. September 2014 um 10:22 Uhr

  • Ich habe gelesen, dass CMake keine nicht rekursiven Makefiles erstellen kann. Ist das noch wahr?

    – Maxim Egorushkin

    12. September 2014 um 15:17 Uhr

  • @Angew Nicht rekursiv ist, wenn make einmal mit vollständiger Projektabhängigkeitsstruktur aufgerufen wird. Im Gegensatz zu rekursiv wenn ein Makefile der obersten Ebene Unterprojekt-Makefiles in einer bestimmten Reihenfolge aufruft.

    – Maxim Egorushkin

    12. September 2014 um 15:24 Uhr

  • Dies ist eine wichtige Schwäche von CMake – GNU make hat seine Tücken, aber wenn Sie sich die Zeit nehmen, es zu lernen, ist es extrem leistungsfähig und vielseitig und funktioniert auf einer enormen Anzahl von Plattformen. Es ist ein großer Fehler, keinen vollständigen Abhängigkeitsbaum zum Analysieren zu haben. Googlen Sie einfach nach “rekursives Make als schädlich”.

    – Erik Alapää

    23. Dezember 2015 um 7:39 Uhr

Benutzeravatar von Victor Sergienko
Viktor Sergijenko

Die Aussage, CMake sei ein „Build-Generator“, ist ein weit verbreitetes Missverständnis.

Es ist technisch nicht falsch; es beschreibt nur WIE es funktioniert, aber nicht WAS es tut.

Im Zusammenhang mit der Frage machen sie dasselbe: Nehmen Sie eine Reihe von C/C++-Dateien und wandeln Sie sie in eine Binärdatei um.

Also, was ist der wirkliche Unterschied?

  • CMake ist viel mehr High-Level. Es ist auf das Kompilieren von C++ zugeschnitten, für das Sie viel weniger Build-Code schreiben, kann aber auch für allgemeine Builds verwendet werden. make hat auch einige eingebaute C/C++-Regeln, aber sie sind bestenfalls nutzlos.

  • CMake führt einen zweistufigen Build durch: Es generiert ein Low-Level-Build-Skript in ninja oder make oder viele andere Generatoren, und dann lässt du es laufen. Alle Shell-Skriptteile, in die normalerweise gestapelt wird Makefile werden nur in der Generierungsphase ausgeführt. Daher, CMake Build kann um Größenordnungen schneller sein.

  • Die Grammatik von CMake ist für externe Tools viel einfacher zu unterstützen als make.

  • Einmal make ein Artefakt baut, vergisst es, wie es gebaut wurde. Aus welchen Quellen wurde es erstellt, welche Compiler-Flags? CMake verfolgt es, make überlässt es dir. Wenn eine der Bibliotheksquellen seit der vorherigen Version von entfernt wurde Makefile, make werde es nicht umbauen.

  • Modern CMake (ab Version 3.irgendwas) funktioniert in Bezug auf Abhängigkeiten zwischen “Zielen”. Ein Ziel ist immer noch eine einzelne Ausgabedatei, aber es kann transitive Abhängigkeiten (“öffentlich”/”Schnittstelle” in CMake-Begriffen) haben. Diese transitiven Abhängigkeiten können den abhängigen Paketen angezeigt oder vor ihnen verborgen werden. CMake verwaltet Verzeichnisse für Sie. Mit makestecken Sie auf einer Datei-für-Datei- und Verzeichnis-von-Hand-Ebene fest.

Du könntest etwas hinein codieren make Verwenden Sie Zwischendateien, um die letzten beiden Lücken zu schließen, aber Sie sind auf sich allein gestellt. make enthält a Turing vollständige Sprache (sogar zwei, manchmal drei zählend List); Die ersten beiden sind schrecklich und die Guile wird praktisch nie benutzt.

Um ehrlich zu sein, das ist was CMake und make gemeinsam haben – ihre Sprachen sind ziemlich schrecklich. Hier ist, was mir in den Sinn kommt:

  • Sie haben keine benutzerdefinierten Typen;
  • CMake hat drei Datentypen: Zeichenfolge, Liste und ein Ziel mit Eigenschaften. make hat eins: string;
  • Normalerweise übergeben Sie Argumente an Funktionen, indem Sie globale Variablen setzen.
    • Dies wird teilweise in modernem CMake behandelt – Sie können die Eigenschaften eines Ziels festlegen: set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}");
  • Verweise auf eine undefinierte Variable werden standardmäßig stillschweigend ignoriert;

  • Einige gute Informationen hier, aber eine Bemerkung ist völlig falsch: cmake hat einen LIST-Typ, da mit richtigen LIST-Funktionen, die für viele Build-System-Aufgaben entscheidend sind, ein kleiner Unterschied besteht: cmake.org/cmake/help/git-master/command/list.html

    – lösenJ

    18. Februar 2020 um 4:01 Uhr

  • @VictorSergienko, nicht in der Frage des OP gestellt, aber ich habe auf die Pointe gewartet … Was verwenden Sie, von dem Sie glauben, dass es besser ist als beides?

    – Robert Lugg

    23. Dezember 2020 um 21:42 Uhr

  • Ich benutze make aus historischen Gründen und ich hasse es. CMake ist auch nicht ohne Probleme (versuchen Sie es mit Cross-Compiling), aber für meine eigenen Projekte würde CMake gewinnen, weil Sie weniger Code schreiben und es von Tools unterstützt wird.

    – Viktor Sergijenko

    24. Dezember 2020 um 1:57 Uhr

  • und lasst automake und autoconf bitte für immer begraben

    – pm100

    1. April um 0:20

Wie in den anderen Antworten erwähnt, kann CMake andere Projektdateien generieren. Es bezeichnet diese Projekte als Generatoren.

Auf diese Weise können Benutzer ihren Build in einer domänenspezifischen Sprache schreiben/beschreiben und den Generator zum Kompilieren des Projekts verwenden. Dies führt häufig zu einfacherem/besserem Code als das direkte Schreiben in diese Projektdateien.

Ein großer Vorteil ist, dass Benutzer das Tool verwenden können, mit dem sie am vertrautesten sind (Makefiles, Visual Studio, XCode, Ninja usw.). Das ist nett, aber argumentierbar führt zu Komplexität. Warum nicht einfach Ninja verwenden?

Die Antwort ist Geschichte. (Wie in C/C++ üblich)

Build-Systeme wie Visual Studio verfügen über Tools, die nur diese Projektdateien akzeptieren.

Zum Beispiel hat Microsoft eine Funktion namens “Static Driver Verifier”. Ein Tool zum Analysieren des Codes von Windows-Treibern im Kernelmodus. Dieses Tool funktioniert jedoch nur in Visual Studio-Projekten, da es parallel funktioniert msbuild.

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

Wenn Ihr Buildsystem keine Visual Studio-Projektdateien generieren kann, können Sie das Tool nicht verwenden. Dies kann ein sehr große Sache für einige Projekte/Unternehmen.

1427880cookie-checkWas ist der Unterschied zwischen der Verwendung eines Makefiles und CMake zum Kompilieren des Codes?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy