Różnica między używaniem Makefile i CMake do kompilowania kodu

288

Piszę na C / C ++ i używam (GNU) Makefile do skompilowania kodu. Mogę zrobić to samo z CMake i uzyskać MakeFile. Jaka jest jednak różnica między użyciem Makefile i CMake do kompilacji kodu?

rish
źródło
2
cmake może także produkować pliki do użycia ninja
BЈовић

Odpowiedzi:

403

Make (a raczej Makefile) to system kompilacji - napędza kompilator i inne narzędzia do budowania kodu.

CMake jest generatorem systemów kompilacji. Może tworzyć pliki Makefile, może tworzyć pliki kompilacji Ninja, może tworzyć projekty KDEvelop lub Xcode, może tworzyć rozwiązania Visual Studio. Z tego samego punktu początkowego ten sam plik CMakeLists.txt. Więc jeśli masz projekt niezależny od platformy, CMake jest sposobem na uczynienie go również niezależnym od systemu.

Jeśli masz programistów Windows przyzwyczajonych do programistów Visual Studio i Unix, którzy przysięgają GNU Make, CMake jest (jest) jedną z wielu dróg.

Zawsze zalecałbym użycie CMake (lub innego generatora kompilacji systemu, ale CMake jest moją osobistą preferencją), jeśli chcesz, aby twój projekt był wieloplatformowy lub szeroko użyteczny. Sam CMake zapewnia także kilka ciekawych funkcji, takich jak wykrywanie zależności, zarządzanie interfejsem biblioteki lub integracja z CTest, CDash i CPack.

Korzystanie z generatora buildsystem sprawia, że ​​projekt jest bardziej przyszłościowy. Nawet jeśli jesteś teraz GNU-Make-only, co jeśli później zdecydujesz się rozszerzyć na inne platformy (Windows lub coś wbudowanego), lub po prostu chcesz użyć IDE?

Angew nie jest już dumny z SO
źródło
5
@rish Tak, to sedno. Zauważ jednak, że istnieje więcej sposobów programowania w Linuksie niż Makefiles - patrz np. QtCreator, KDEvelop, Ninja. Dla każdego z nich albo „utwórz projekt i zsynchronizuj go z Makefile”, albo „uruchom ponownie CMake”. I, jak wspomniano w odpowiedzi, CMake ma również inne funkcje, takie jak wykrywanie zależności (np. find_package()) Lub obsługa testowania / pakowania.
Angew nie jest już dumny z SO
3
Czytałem, że CMake nie może tworzyć nierekurencyjnych plików makefile. Czy to nadal prawda?
Maxim Egorushkin
1
@Angew nierekursywnych jest, gdy marka jest wywoływana raz z kompletnym drzewie zależności projekt. W przeciwieństwie do rekurencyjnego, gdy makefile najwyższego poziomu wywołuje makefile podprojektu w określonej kolejności.
Maxim Egorushkin
3
Jest to ważna słabość CMake - GNU make ma swoje zmarszczki, ale jeśli poświęcisz trochę czasu, aby się go nauczyć, jest on niezwykle potężny i wszechstronny i działa na ogromnej liczbie platform. Brak pełnego drzewa zależności do analizy jest poważną wadą, wystarczy wyszukać w Google „rekurencyjne uznają za szkodliwe”.
Erik Alapää
1
@ ErikAlapää Przeczytam ten artykuł szczegółowo, ale na pierwszy rzut oka - wydają się mówić o marce rekurencyjnej, w której głębokość rekurencji zależy od danych (tzn. Zależy od głębokości katalogu źródłowego itp.). Nie jest tak w przypadku CMake: całkowita głębokość wywołań make wynosi zawsze 3, niezależnie od struktury projektu. Tyle tylko, że niektóre bity są delegowane do pliku podrzędnego zamiast wszystkich w jednym, ale nie odzwierciedla to w żaden sposób struktury projektu. Ponadto pliki podrzędne nie są tak naprawdę „samowystarczalne”, więc nie cierpią z powodu problemu zbyt dużej / zbyt małej zależności.
Angew nie jest już dumny z SO
39

Stwierdzenie o tym, że CMake jest „generatorem kompilacji”, jest powszechnym nieporozumieniem.

To nie jest technicznie złe; po prostu opisuje JAK to działa, ale nie CO JEST.

W kontekście pytania robią to samo: weź kilka plików C / C ++ i zamień je w plik binarny.

Jaka jest prawdziwa różnica?

  • CMake ma znacznie wyższy poziom. Jest przystosowany do kompilacji C ++, dla której piszesz o wiele mniej kodu kompilacji, ale może być również używany do kompilacji ogólnego przeznaczenia. makema także pewne wbudowane reguły C / C ++, ale są one w większości bezużyteczne.

  • CMakewykonuje kompilację dwuetapową: generuje skrypt kompilacji niskiego poziomu w ninjalub w makewielu innych generatorach, a następnie uruchamiasz go. Wszystkie elementy skryptu powłoki, które są zwykle ułożone w stos, Makefilesą wykonywane tylko na etapie generowania. W ten sposób CMakekompilacja może być o rząd wielkości szybsza.

  • Gramatyka CMakejest znacznie łatwiejsza do obsługi narzędzi zewnętrznych niż make .

  • Po makezbudowaniu artefaktu zapomina, jak go zbudowano. Z jakich źródeł został zbudowany, z jakich flag kompilatora? CMakeśledzi to, makepozostawia to tobie. Jeśli jedno ze źródeł biblioteki zostało usunięte od poprzedniej wersji Makefile, makenie odbuduje go.

  • Nowoczesne CMake(począwszy od wersji 3. coś) działa w kategoriach zależności między „celami”. Cel jest nadal pojedynczym plikiem otput (niestety), ale może mieć zależności przechodnie („publiczny” / „interfejs” w kategoriach CMake). Te zależności przechodnie można ujawnić lub ukryć przed pakietami zależnymi. CMakezarządza również katalogami dla Ciebie. Dzięki makeutkniesz na poziomie plik po pliku i zarządzasz katalogami ręcznie.

Możesz zakodować coś przy makeużyciu plików flag do pokrycia dwóch ostatnich luk, ale jesteś sam. makezawiera kompletny język Turinga (nawet dwa, czasem trzy, podstępne ), a wszystkie z nich są okropne.

Szczerze mówiąc, to co CMakei makemają wspólną cechę - ich języki są dość straszne:

  • Nie mają typów;
  • bez tablic, tylko łańcuchy oddzielone spacją, co pozwala uniknąć piekła;
  • zwykle przekazujesz argumenty do funkcji ustawiając zmienne globalne; (jest to rozwiązywane we współczesnym CMake - zmienne mogą teraz mieć przestrzenie nazw; celem jest obszar nazw dla jego właściwości)
  • odwoływanie się do niezdefiniowanej zmiennej jest domyślnie ignorowane;

zacząć z.

Ale CMakepiszesz o wiele mniej wierszy kodu.

Victor Sergienko
źródło
1
Kilka dobrych informacji tutaj, ale jedna uwaga jest całkowicie błędna: cmake ma typ LISTY, ponieważ z odpowiednimi funkcjami LISTY, która jest kluczowa dla wielu zadań kompilacji systemu, mała różnica: cmake.org/cmake/help/git-master/command /list.html
rozwiązywanieJ
Nie nazwałbym tego „całkowicie” błędnym, ale dziękuję za korektę.
Victor Sergienko