Cmake

Ten dokument zawiera szybki przegląd CMake – wieloplatformowej alternatywy dla linuksowych Makefile i make. Pomoc w używaniu make i Makefile bez CMake można znaleźć w dokumentacji profesora Newhalla. Ten dokument został napisany dla wersji 2.6 cmake, która jest instalowana na maszynach laboratoryjnych poprzez stow (od stycznia 2009).

Dlaczego CMake

Ja osobiście lubię CMake ponieważ wydaje się bardziej intuicyjny niż pisanie standardowego pliku Makefile. Podstawowe i powszechne rzeczy są dość łatwe, a trudniejsze są możliwe, choć większość rzeczy, które buduję jest dość podstawowa. Aby zademonstrować CMake, dołączyłem trochę przykładowego kodu w pliku cmake.tgz (4 KB). Zapisz plik i rozpakuj jego zawartość w dowolnym miejscu w swoim katalogu. Na przykład:

$ tar xzvf cmake.tgz$ cd cmake$ lsCMakeLists.txt w01-cpp/
CMakeLists.txt

CMake jest kontrolowany przez zapisywanie instrukcji w plikach CMakeLists.txt. Każdy katalog w twoim projekcie powinien mieć plik CMakeLists.txt. To co jest fajne w CMake to fakt, że pliki CMakeLists.txt w podkatalogu dziedziczą właściwości ustawione w katalogu nadrzędnym, redukując ilość duplikacji kodu. Dla naszego przykładowego projektu, mamy tylko jeden podkatalog: w01-cpp. Plik CMakeLists.txt dla katalogu cmake na najwyższym poziomie jest dość prosty, ale demonstruje kilka kluczowych właściwości.

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)

Ten kod demo zawiera kod, który wymaga zewnętrznych bibliotek OpenGL do grafiki. W typowej konfiguracji pliku Makefile prawdopodobnie musielibyśmy określić gdzie znajdują się pliki nagłówkowe OpenGL, np. -I/usr/local/include, jakich bibliotek użyć, np. -lGL -lGLU -lglut, oraz lokalizację bibliotek. Lokalizacja plików nagłówkowych i bibliotek prawdopodobnie różni się w zależności od instalacji i platformy. Zazwyczaj jednak istnieją pewne standardowe miejsca, w których należy szukać, a CMake automatyzuje to wyszukiwanie za pomocą makr find_package. Tak więc find_package(GLUT) i find_package(OpenGL) znajdują lokalizację plików nagłówkowych i bibliotek oraz ustawiają najbardziej powszechne biblioteki, które są linkowane w typowym projekcie OpenGL. CMake posiada wsparcie dla znajdowania wielu pakietów. Więcej przykładów można znaleźć w /usr/local/share/cmake-2.6/Modules/Find*.cmake. Aby użyć jednego z tych skryptów, użyj find_package(PKGname) jeśli skrypt CMake nazywa się FindPKGname.cmake.

Więcej na temat znajdowania zewnętrznych bibliotek lub tworzenia własnych makr find package, zobacz wiki KitWare na ten temat.

Możesz ustawić zwykłe flagi, które ustawiłbyś w typowym pliku Makefile używającingset(VARNAME VALUE). W tym przykładzie włączyłem symbole debugowania (-g) i wszystkie ostrzeżenia (-Wall). Nadałem również nazwę temu projektowi CMake używając project(CMAKEDEMO). Możesz nazwać swój projekt jak tylko chcesz. Użyjemy tej informacji w pliku CMakeLists.txt znajdującym się w katalogu w01-cpp. Na koniec zaznaczamy, że większość kodu znajduje się w katalogu w01-cpp, mówiąc naszemu nadrzędnemu plikowi CMakeLists.txt, aby add_subdirectory(w01-cpp)

Przyjrzyjrzyjmy się plikowi CMakeLists.txt w podkatalogu 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)

Makro include_directories mówi CMake, gdzie szukać plików źródłowych. Deklarując nazwę projektu CMAKEDEMO w nadrzędnym pliku CMakeLists.txt, zmienne CMAKEDEMO_SOURCE_DIR i CMAKEDEMO_BINARY_DIR są ustawiane w zależności od bieżącej lokalizacji twojego kodu i bieżącej lokalizacji twojego katalogu budowania (więcej o tej drugiej lokalizacji później). Dodanie celu dla nowego binarnego pliku wykonywalnego jest proste. Wystarczy dodać linię add_executable(cdemo cdemo.c). CMake automatycznie dobierze kompilator na podstawie rozszerzenia typu pliku. Jeśli potrzebne są dodatkowe biblioteki, możesz powiedzieć CMake aby się z nimi połączył używając target_link_libraries(cdemo m). To mówi CMake, że program cdemo musi być połączony z biblioteką matematyczną. Można łączyć się z więcej niż jedną biblioteką, podając je w postaci listy. Zobacz na przykład set(CORELIBS ${GLUT_LIBRARY} ${OPENGL_LIBRARY} m). Zmienne GLUT_LIBRARY i OPENGL_LIBRARY zostały ustawione przez CMake gdy użyliśmy funkcji find_package(GLUT) i find_package(OpenGL). Aby dowiedzieć się, które zmienne są ustawiane przy użyciu find_package, prawdopodobnie będziesz musiał otworzyć odpowiedni plik Find*.cmake i przeczytać zazwyczaj pomocną, lecz lakoniczną dokumentację.

Ponieważ kilka programów w folderze w01-cpp jest skompilowanych w ten sam sposób i połączonych z tymi samymi bibliotekami, możemy przetworzyć je wszystkie za pomocą prostej pętli pokazanej powyżej, używając makra foreach w CMake. Na koniec pokażemy jak stworzyć własną bibliotekę używając add_library(geometriageometrii.cpp) i łącząc się z tą biblioteką w target_link_libraries(test_geometrii ${CORELIBS}geometrii).

Budowanie za pomocą CMake

Ustawienie kilku plików CMakeLists.txt nie pozwoli ci od razu zbudować twojego projektu. CMake jest tylko międzyplatformową nakładką na bardziej tradycyjne systemy budowania. W przypadku linuxa, oznacza to make. Szybki krok przetwarzania wstępnego automatycznie przekształci Twój opis CMakeLists.txt w tradycyjny system budowania make. Jedną z miłych i wysoce zalecanych cech CMake jest możliwość budowania poza źródłem. W ten sposób możesz tworzyć wszystkie pliki .o, różne tymczasowe pliki zależności, a nawet binarne pliki wykonywalne bez zagracania drzewa źródeł. Aby użyć kompilacji poza źródłem, utwórz katalog kompilacji w folderze najwyższego poziomu (technicznie rzecz biorąc, może to być gdziekolwiek, ale folder projektu najwyższego poziomu wydaje się być logicznym wyborem). Następnie przejdź do swojego katalogu build i uruchom cmake wskazując na katalog najwyższego poziomu CMakeLists.txt. Na przykład:

cumin$ cd cmake/cumin$ lsCMakeLists.txt w01-cpp/cumin$ mkdir buildcumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ cd build/cumin$ cmake ..

Pamiętaj, aby być w swoim katalogu budowania i wskazać cmake tylko na katalog zawierający plik CMakeLists.txt najwyższego poziomu, a nie na sam plik. Jeśli wszystko pójdzie dobrze, cmake przetworzy twoje pliki CMakeLists.txt, znajdzie lokalizację wszystkich bibliotek i ścieżek dołączania oraz wypluje garść informacji konfiguracyjnych, w tym tradycyjny plik Makefile w twoim katalogu budowania. (Jeśli znasz autotools/autohell, ten proces cmake jest podobny do ./configure). Teraz jesteś gotowy do budowania przy użyciu tradycyjnego systemu make. Uruchom make w swoim katalogu build, aby wszystko skompilować i połączyć. CMake podrzuca nawet kilka ładnych kolorów, paski postępu i tłumi wiele danych wyjściowych gcc. Jeśli chcesz mieć pełne dane wyjściowe, możesz wpisać VERBOSE=1 make (pomocne jeśli coś pójdzie nie tak).

Ze względu na sposób w jaki skonfigurowaliśmy build out of source i link_directories(${CMAKEDEMO_BINARY_DIR}/w01-cpp), nasze świeżo skompilowane binarki znajdują się w folderze w01-cpp w katalogu build, w którym właśnie uruchomiliśmy 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 

Wciśnij ESC aby wyjść z dema OpenGL.

Podsumowanie

Jeśli zmodyfikujesz kod w swoim katalogu źródłowym, włączając w to nawet plik CMakeLists.txt i ponownie uruchomisz make w katalogu budowania, make i cmake ponownie skompilują i odbudują niezbędne zmiany. Jeśli dokonujesz zmian tylko w podkatalogu, możesz po prostu uruchomić make w odpowiednim podkatalogu w drzewie budowania, aby przetworzyć aktualizacje.

Początkowym źródłem zamieszania przy kompilacji poza źródłem jest to, że w zasadzie masz dwie kopie swojego drzewa źródłowego, jedną z rzeczywistym kodem źródłowym, a drugą z plikami Makefile i binarnymi plikami wykonywalnymi (w drzewie kompilacji). Prawdopodobnie najlepiej jest mieć otwarte dwa okna, jedno w drzewie kompilacji do tworzenia i uruchamiania programów, a drugie w drzewie źródłowym do modyfikowania plików źródłowych.

Jedną miłą rzeczą w kompilacjach bez źródła jest to, że czyszczenie plików obiektów, plików makedepend, plików binarnych i innych różnych elementów kompilacji może być wykonane przez proste usunięcie całego katalogu kompilacji, ponieważ nie ma tam źródła. Możesz także użyć make clean do wyczyszczenia rzeczywistych plików obiektowych i binarnych, ale kiedy planujesz spakować swoje źródła lub rozprowadzić swój kod do mas, możesz po prostu

cumin$ cd cmakecumin$ lsCMakeLists.txt build/ w01-cpp/cumin$ rm -rf build/cumin$ lsCMakeLists.txt w01-cpp/

wyczyścić i spakować swój kod.

Więcej do odkrycia

To tylko dotknięcie powierzchni tego, co CMake potrafi. Sprawdź CMake Wiki po więcej informacji. Mam nadzieję, że będę aktualizował tę stronę, jeśli natrafimy na bardziej złożone przykłady, i chętnie przyjmę opinie lub wskazówki od innych kursów, które mogą używać CMake. Dla bardzo zaawansowanych użytkowników, CMake posiada towarzyszący program CPack do automatycznego pakowania binariów i źródeł dla systemów Ubuntu/Debian (.deb), Red Hat (.rpm), OSXX11, tgz, CygWin i Nullsoft.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.