Differenza tra l'utilizzo di Makefile e CMake per compilare il codice


288

I codice su C / C ++ e utilizzo un Makefile (GNU) per compilare il codice. Posso fare lo stesso con CMake e ottenere un MakeFile. Tuttavia, qual è la differenza tra l'utilizzo di Makefile e CMake per compilare il codice?


2
cmake può anche produrre file per usare ninja
BЈовић

Risposte:


403

Make (o piuttosto un Makefile) è un sistema di compilazione - guida il compilatore e altri strumenti di compilazione per costruire il tuo codice.

CMake è un generatore di buildsystems. Può produrre Makefile, può produrre file di build Ninja, può produrre progetti KDEvelop o Xcode, può produrre soluzioni di Visual Studio. Dallo stesso punto di partenza, lo stesso file CMakeLists.txt. Quindi, se hai un progetto indipendente dalla piattaforma, CMake è anche un modo per renderlo indipendente dal sistema.

Se hai sviluppatori Windows abituati a sviluppatori Visual Studio e Unix che giurano su GNU Make, CMake è (una delle) strade da percorrere.

Consiglierei sempre di usare CMake (o un altro generatore di buildsystem, ma CMake è la mia preferenza personale) se intendi che il tuo progetto sia multipiattaforma o ampiamente utilizzabile. CMake stesso offre anche alcune funzioni interessanti come il rilevamento delle dipendenze, la gestione dell'interfaccia della libreria o l'integrazione con CTest, CDash e CPack.

L'uso di un generatore di buildsystem rende il progetto più a prova di futuro. Anche se sei GNU-Make-only ora, cosa succederebbe se in seguito decidessi di espanderti su altre piattaforme (sia Windows o qualcosa di incorporato) o desideri semplicemente utilizzare un IDE?


5
@rish Sì, questo è il senso. Nota comunque che ci sono più modi di programmare su Linux che Makefile - vedi ad esempio QtCreator, KDEvelop, Ninja. Per ognuno di questi, è "creare un progetto e mantenerlo sincronizzato con il Makefile" o "rieseguire CMake". E, come afferma la risposta, CMake ha anche altre funzionalità, come il rilevamento delle dipendenze (ad es. find_package()) O il supporto di test / packaging.
Angew non è più orgoglioso di SO

3
Ho letto che CMake non può creare makefile non ricorsivi. È ancora vero?
Maxim Egorushkin,

1
@Angew Non ricorsivo è quando make viene invocato una volta con l'albero delle dipendenze del progetto completo. Al contrario di ricorsivo quando un makefile di livello superiore invoca i makefile del sottoprogetto in un certo ordine.
Maxim Egorushkin,

3
Questa è un'importante debolezza di CMake - GNU make ha le sue rughe, ma se ti prendi il tempo per impararlo, è estremamente potente e versatile e funziona su un'enorme quantità di piattaforme. Non avere un albero delle dipendenze completo da analizzare è un grosso difetto, solo Google per "ricorsivo è considerato dannoso".
Erik Alapää,

1
@ ErikAlapää Leggerò l'articolo in dettaglio, ma da una prima occhiata - sembrano parlare di marca ricorsiva in cui la profondità della ricorsione è guidata dai dati (cioè dipende dalla profondità della directory di origine ecc.). Non è il caso di CMake: la profondità totale delle invocazioni è sempre 3, indipendentemente dalla struttura del progetto. È solo che alcuni bit vengono delegati a un file secondario anziché a tutti in uno, ma non riflette in alcun modo la struttura del progetto. Inoltre, i file secondari non sono realmente "autonomi", quindi non soffrono del problema di dipendenza eccessiva / insufficiente.
Angew non è più orgoglioso del

39

L'affermazione che CMake sia un "generatore di build" è un malinteso comune.

Non è tecnicamente sbagliato; descrive semplicemente COME funziona, ma non COSA funziona.

Nel contesto della domanda, fanno la stessa cosa: prendono un sacco di file C / C ++ e li trasformano in un file binario.

Quindi, qual è la vera differenza?

  • CMake è molto più di alto livello. È su misura per compilare C ++, per il quale si scrive molto meno codice di compilazione, ma può essere utilizzato anche per la compilazione generica. makeha anche alcune regole C / C ++ integrate, ma sono per lo più inutili.

  • CMakefa un accumulo in due fasi: genera uno script di build di basso livello in ninjao makeo molti altri generatori, e poi lo si esegue. Tutti i pezzi di script shell che sono normalmente ammucchiati Makefilevengono eseguiti solo nella fase di generazione. Pertanto, CMakebuild può essere più veloce di ordini di grandezza.

  • La grammatica di CMakeè molto più facile da supportare per strumenti esterni rispetto a quelli di make .

  • Una volta makecostruito un artefatto, si dimentica come è stato costruito. Da quali fonti è stato costruito, quali flag del compilatore? CMakelo segue, lo makelascia a te. Se una delle fonti della libreria è stata rimossa dalla versione precedente di Makefile, makenon la ricostruirà.

  • Moderno CMake(a partire dalla versione 3.qualcosa) funziona in termini di dipendenze tra "obiettivi". Un target è ancora un singolo file otput (purtroppo), ma può avere dipendenze transitive ("pubblico" / "interfaccia" in termini di CMake). Queste dipendenze transitive possono essere esposte o nascoste dai pacchetti dipendenti. CMakegestirà le directory anche per te. Con make, sei bloccato a livello di file per file e gestisci le directory per mano.

Puoi codificare qualcosa makeusando i file flag per coprire gli ultimi due spazi vuoti, ma sei da solo. makecontiene un linguaggio completo di Turing (anche due, a volte tre contando Guile ), e sono tutti orribili.

Ad essere sinceri, questo è ciò CMakeche makehanno in comune: le loro lingue sono piuttosto orribili:

  • Non hanno tipi;
  • nessuna matrice, solo stringhe separate dallo spazio, in modo da sfuggire all'inferno;
  • normalmente si passano argomenti alle funzioni impostando variabili globali; (questo è stato affrontato nel moderno CMake: le variabili possono ora avere un namespace; un target è uno spazio dei nomi per le sue proprietà)
  • il riferimento a una variabile non definita viene silenziosamente ignorato per impostazione predefinita;

iniziare con.

Ma in CMakete scrivi molte meno righe di codice.


1
Alcune buone informazioni qui, ma un'osservazione è completamente sbagliata: cmake ha un tipo di ELENCO poiché con le corrette funzioni di ELENCO che è cruciale per molte attività del sistema di build, una piccola differenza: cmake.org/cmake/help/git-master/command /list.html
risoluzione del

Non lo definirei "completamente" sbagliato, ma grazie per la correzione.
Victor Sergienko,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.