Detta dokument ger en snabb översikt över CMake – ett plattformsoberoende alternativ till Linux Makefiles och make. För hjälp med att använda make och Makefiles utan CMake, se professor Newhalls dokumentation. Det här dokumentet skrevs för cmake version 2.6, som installeras på labbmaskinerna via stow (från och med januari 2009).
Personligen gillar jag CMake eftersom det verkar mer intuitivt än att skriva en vanlig Makefile. Grundläggande och vanliga saker är ganska enkla och svårare saker är möjliga, även om det mesta jag bygger är ganska grundläggande. För att demonstrera CMake har jag inkluderat lite exempelkod i filen cmake.tgz (4 KB). Spara filen och packa upp innehållet var som helst i din katalog. Till exempel:
$ tar xzvf cmake.tgz$ cd cmake$ lsCMakeLists.txt w01-cpp/
CMake styrs genom att skriva instruktioner i CMakeLists.txt-filer. Varje katalog i ditt projekt bör ha en CMakeLists.txt-fil. Det fina med CMake är att CMakeLists.txt-filer i en underkatalog ärver egenskaper som har ställts in i den överordnade katalogen, vilket minskar mängden koddubblering. För vårt exempelprojekt har vi bara en underkatalog: w01-cpp. CMakeLists.txt-filen för den översta cmake-katalogen är ganska enkel men visar några viktiga funktioner.
cmake_minimum_required(VERSION 2.6)project(CMAKEDEMO)#There are lots of scripts with cmake#for finding external libraries. #see /usr/local/share/cmake-2.6/Modules/Find*.cmake for more examplesfind_package(GLUT)find_package(OpenGL)set(CMAKE_CXX_FLAGS "-g -Wall")add_subdirectory(w01-cpp)
Denna demokod innehåller kod som kräver externa OpenGL-bibliotek för grafik. I en typisk Makefile-konfiguration skulle vi sannolikt behöva ange var OpenGL-headerfilerna finns, t.ex. -I/usr/local/include, vilka bibliotek som ska användas, t.ex. -lGL -lGLU -lglut, och var biblioteken finns. Placeringen av headerfilerna och biblioteken varierar sannolikt från installation till installation och från plattform till plattform. Det finns dock vanligtvis några standardställen att leta på, och CMake automatiserar denna sökning med hjälp av makron find_package. Således hittar find_package(GLUT) och find_package(OpenGL) platsen för headerfilerna och biblioteken och ställer in de vanligaste biblioteken som länkas till i ett typiskt OpenGL-projekt. CMake har stöd för att hitta många paket. Se /usr/local/share/cmake-2.6/Modules/Find*.cmake för fler exempel. För att använda ett av dessa skript använder du find_package(PKGname) om CMake-skriptet heter FindPKGname.cmake.
För mer information om att hitta externa bibliotek eller skapa egna find package-makron, se KitWare-wikin om ämnet.
Du kan ställa in vanliga flaggor som du skulle ställa in i en typisk Makefile med hjälp av användingset(VARNAME VALUE). I det här exemplet aktiverade jag felsökningssymboler (-g) och alla varningar (-Wall). Jag gav också det här CMake-projektet ett namn med hjälp av project(CMAKEDEMO). Du kan namnge ditt projekt som du vill. Vi kommer att använda denna information i filen CMakeLists.txt i katalogen w01-cpp. Slutligen anger vi att det mesta av koden egentligen finns i w01-cpp genom att säga till vår CMakeLists.txt-fil på högsta nivå att add_subdirectory(w01-cpp)
Låt oss ta en titt på CMakeLists.txt-filen i underkatalogen w01-cpp:
include_directories(${CMAKEDEMO_SOURCE_DIR}/w01-cpp)link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp)#the one C fileadd_executable(cdemo cdemo.c)target_link_libraries(cdemo m) #link the math library#these are all compiled the same wayset(PROGRAMS oglfirst pointers)set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m)foreach(program ${PROGRAMS}) add_executable(${program} ${program}.cpp) target_link_libraries(${program} ${CORELIBS})endforeach(program)#building just a library. add_library(geometry geometry.cpp)add_executable(test_geometry test_geometry.cpp)#linking against a custom librarytarget_link_libraries(test_geometry ${CORELIBS} geometry)
Makroet include_directories talar om för CMake var CMake ska leta efter källkodsfiler. Genom att deklarera projektnamnet CMAKEDEMO i den översta CMakeLists.txt-filen sätts variablerna CMAKEDEMO_SOURCE_DIR och CMAKEDEMO_BINARY_DIR beroende på den aktuella platsen för din kod och den aktuella platsen för din byggkatalog (mer om den senare platsen senare). Det är enkelt att lägga till ett mål för en ny binär körbar fil. Lägg bara till en rad add_executable(cdemo cdemo.c). CMake kommer automatiskt att räkna ut kompilatorn baserat på filtyptillägget. Om ytterligare bibliotek behövs kan du säga till CMake att länka mot dem med target_link_libraries(cdemo m). Detta talar om för CMake att cdemo-programmet måste länkas mot det matematiska biblioteket. Du kan länka mot mer än ett bibliotek genom att ange biblioteken i en lista. Se till exempel set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m). Variablerna GLUT_LIBRARY och OPENGL_LIBRARY sätts av CMake när vi använde find_package(GLUT) och find_package(OpenGL). För att ta reda på vilka variabler som sätts när du använder find_package måste du förmodligen öppna den lämpliga filen Find*.cmake och läsa den vanligtvis hjälpsamma men kortfattade dokumentationen.
Då flera program i den här mappen w01-cpp kompileras på samma sätt och länkas mot samma bibliotek kan vi behandla dem alla med en enkel slinga som visas ovan med hjälp av foreach-makrot i CMake. Slutligen visar vi hur vi skapar vårt eget bibliotek med hjälp av add_library(geometry geometry.cpp) och länkar mot detta bibliotek i target_link_libraries(test_geometry ${CORELIBS} geometry).
Att sätta upp en massa CMakeLists.txt-filer gör att du inte omedelbart kan bygga ditt projekt. CMake är bara en plattformsoberoende omslagsform för mer traditionella byggsystem. I fallet Linux innebär detta make. Ett snabbt förbehandlingssteg kommer att konvertera din CMakeLists.txt-beskrivning till ett traditionellt make-byggsystem automatiskt. En trevlig och starkt rekommenderad funktion i CMake är möjligheten att göra out of source builds. På detta sätt kan du göra alla dina .o-filer, olika temporära beroendefiler och till och med de binära körbara filerna utan att stöka till ditt källkodsträd. För att använda out of source builds skapar du en build-katalog i din mapp på högsta nivå (tekniskt sett kan detta vara var som helst, men projektmappen på högsta nivå verkar vara ett logiskt val). Byt sedan till din byggkatalog och kör cmake och peka på katalogen för CMakeLists.txt på den högsta nivån. Till exempel:
cumin$ cd cmake/cumin$ lsCMakeLists.txt w01-cpp/cumin$ mkdir buildcumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ cd build/cumin$ cmake ..
Håll dig i din byggkatalog och kom ihåg att peka cmake endast till katalogen som innehåller toppnivåns CMakeLists.txt-fil, inte själva filen. Om allt går bra kommer cmake att bearbeta dina CMakeLists.txt-filer, hitta platsen för alla bibliotek och inkluderingsvägar och spotta ut en massa konfigurationsinformation, inklusive en traditionell Makefile i din byggkatalog. (Om du är bekant med autotools/autohell så liknar denna cmake-process ./configure). Du är nu redo att bygga med hjälp av det traditionella make-systemet. Kör make i din byggkatalog för att kompilera och länka allting. CMake slänger till och med in några trevliga färger, framstegsbalkar och undertrycker en massa gcc-utdata. Om du vill ha verbose-utdata kan du skriva VERBOSE=1 make (användbart om något går fel).
På grund av hur vi ställde in out of source build och link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp) finns våra nykompilerade binärer i mappen w01-cpp i byggkatalogen där vi just körde make.
cumin$ cd w01-cpp/cumin$ lsCMakeFiles/ cdemo* libgeometry.a pointers*Makefile cmake_install.cmake oglfirst* test_geometry*cumin$ ./cdemo Sqrt(2) = 1.4142 This concludes a short C democumin$ ./oglfirst cumin$ ./test_geometry
Tryck på ESC för att avsluta OpenGL-demonstrationerna.
Om du ändrar koden i källkatalogen, inklusive till och med en CMakeLists.txt-fil, och kör make på nytt i byggkatalogen, kommer make och cmake att kompilera om och bygga om nödvändiga ändringar. Om du bara gör ändringar i en underkatalog kan du helt enkelt köra make i motsvarande underkatalog i byggträdet för att bearbeta uppdateringar.
En inledande källa till förvirring med out of source builds är att du i princip har två kopior av ditt källkodsträd, en med den faktiska källkoden och en med Makefiles och binära körbara filer (i build tree). Det är förmodligen bäst att hålla två fönster öppna med ett i byggträdet för att göra och köra dina program och ett fönster i källkodsträdet för att ändra källkodsfiler.
En trevlig sak med out of source builds är att rensning av objektfiler, makedepend-filer, binärfiler och annan diverse byggskräp kan göras genom att helt enkelt radera hela byggkatalogen eftersom det inte finns någon källkod. Du kan också använda make clean för att rensa upp de faktiska objekt- och binärfilerna, men när du planerar att tjära upp din källa eller distribuera din kod till massorna kan du helt enkelt göra
cumin$ cd cmakecumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ rm -rf build/cumin$ lsCMakeLists.txt w01-cpp/
att rensa upp och paketera din kod.
Detta rör bara vid ytan av vad CMake kan göra. Kolla in CMake Wiki för mer information. Jag hoppas kunna uppdatera den här sidan om vi stöter på mer komplexa exempel, och jag tar gärna emot feedback eller tips från andra kurser som kanske använder CMake. För mycket avancerade användare har CMake ett kompanjonprogram CPack för automatisk paketering av binärer och källkod för Ubuntu/Debian (.deb), Red Hat (.rpm), OSXX11, tgz, CygWin och Nullsoft-system.