Ich programmiere in C/C++ und verwende ein (GNU) Makefile, um den Code zu kompilieren. Ich kann dasselbe mit CMake tun und ein Makefile erstellen. Was ist jedoch der Unterschied zwischen der Verwendung eines Makefiles und CMake zum Kompilieren des Codes?
Antworten
Zu viele Anzeigen?Machen (oder besser gesagt 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 erstellen, Ninja-Build-Dateien erstellen, KDEvelop oder Xcode-Projekte erstellen, Visual Studio-Lösungen erstellen. Aus dem gleichen Ausgangspunkt, der gleichen CMakeLists.txt-Datei. Wenn Sie also ein plattformunabhängiges Projekt haben, ist CMake auch eine Möglichkeit, es unabhängig vom Buildsystem zu machen.
Wenn Sie Windows-Entwickler haben, die Visual Studio gewohnt sind, und Unix-Entwickler, die auf GNU Make schwören, ist CMake (einer) der Wege, die Sie gehen können.
Ich würde immer empfehlen, CMake (oder einen anderen Buildsystem-Generator, aber CMake ist meine persönliche Präferenz) zu verwenden, wenn Sie Ihr Projekt plattformübergreifend oder weit verbreitet machen möchten. 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 zukunftssicher. Selbst wenn Sie im Moment nur GNU-Make verwenden, was ist, wenn Sie später beschließen, auf andere Plattformen (sei es Windows oder etwas eingebettetes) zu erweitern oder einfach nur eine IDE verwenden möchten?
Die Aussage, dass CMake ein "Build-Generator" ist, ist ein häufiges Missverständnis.
Technisch gesehen ist es nicht falsch; es beschreibt nur, WIE es funktioniert, aber nicht, WAS es macht.
Im Kontext der Frage tun sie dasselbe: Sie nehmen eine Reihe von C/C++-Dateien und wandeln sie in ein Binärformat um.
Also, was ist der wirkliche Unterschied?
-
CMake ist viel höherstufiger. Es wurde dafür entwickelt, C++ zu kompilieren, für das Sie viel weniger Build-Code schreiben müssen, kann aber auch für den allgemeinen Build verwendet werden.
make
hat auch einige integrierte C/C++-Regeln, aber sie sind bestenfalls nutzlos. -
CMake
führt einen zweistufigen Build durch: Es generiert ein Low-Level-Build-Skript inninja
odermake
oder vielen anderen Generatoren, und dann führen Sie es aus. Alle Shell-Skript-Teile, die normalerweise in eineMakefile
gesteckt werden, werden nur in der Generierungsphase ausgeführt. Daher kann einCMake
-Build um Größenordnungen schneller sein. -
Die Grammatik von
CMake
ist für externe Tools einfacher zu unterstützen als die von make. -
Wenn
make
ein Artefakt erstellt, vergisst es, wie es erstellt wurde. Aus welchen Quellen wurde es erstellt, welche Compiler-Flags?CMake
verfolgt es,make
überlässt es Ihnen. Wenn eine Bibliotheksquelle seit der vorherigen Version vonMakefile
entfernt wurde, wirdmake
sie nicht neu erstellen. -
Modernes
CMake
(beginnend mit Version 3.irgendwas) funktioniert in Bezug auf Abhängigkeiten zwischen "Zielen". Ein Ziel ist immer noch eine einzelne Ausgabedatei, kann aber transitive ("öffentliche"/"Schnittstelle" in CMake-Begriffen) Abhängigkeiten haben. Diese transitiven Abhängigkeiten können den abhängigen Paketen freigelegt oder verborgen werden.CMake
verwaltet Verzeichnisse für Sie. Mitmake
sind Sie auf einer Datei-für-Datei- und Verzeichnis-verwaltung-per-Hand-Ebene stecken geblieben.
Sie könnten mit make
etwas codieren, indem Sie Zwischendateien verwenden, um die letzten beiden Lücken zu schließen, aber Sie sind auf sich allein gestellt. make
enthält eine Turing-vollständige Sprache (sogar zwei, manchmal drei, wenn man Guile zählt); die ersten beiden sind schrecklich und das Guile wird praktisch nie verwendet.
Um ehrlich zu sein, das ist das, was CMake
und make
gemeinsam haben - ihre Sprachen sind ziemlich schrecklich. Hier ist, was mir einfällt:
- Sie haben keine benutzerdefinierten Typen;
CMake
hat drei Datentypen: String, Liste und ein Ziel mit Eigenschaften.make
hat nur einen: String;- Sie übergeben normalerweise Argumente an Funktionen, indem Sie globale Variablen setzen.
- Dies wird teilweise in modernem CMake behandelt - Sie können die Eigenschaften eines Ziels setzen:
set_property(TARGET helloworld APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}")
;
- Dies wird teilweise in modernem CMake behandelt - Sie können die Eigenschaften eines Ziels setzen:
- Auf eine nicht definierte Variable zu verweisen wird standardmäßig stillschweigend ignoriert;
Wie in den anderen Antworten erwähnt, kann CMake andere Projektdateien generieren. Es bezieht sich auf diese Projekte als Generatoren.
Dies ermöglicht es Benutzern, ihren Build mit einer domänenspezifischen Sprache zu schreiben/beschreiben und den Generator zum Kompilieren des Projekts zu verwenden. Dies führt oft 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, etc). Das ist schön, aber es führt möglicherweise zu Komplexität. Warum also nicht einfach Ninja verwenden?
Die Antwort ist die Geschichte. (Wie üblich in C/C++)
Build-Systeme wie Visual Studio haben Tools, die nur diese Projektdateien akzeptieren.
Zum Beispiel hat Microsoft eine Funktion namens "Static Driver Verifier". Ein Tool zur Analyse des Codes von Kernelmodus-Windows-Treibern. Dieses Tool funktioniert jedoch nur mit Visual Studio-Projekten, da es zusammen mit msbuild
arbeitet.
msbuild /t:sdv /p:Inputs="Parameters" Projektdatei /p:Configuration=Konfiguration /p:Platform=Plattform
Wenn Ihr Build-System keine Visual Studio-Projektdateien generieren kann, können Sie das Tool nicht verwenden. Das kann für einige Projekte/Unternehmen ein sehr großes Problem sein.