Wersja minimalna
Tutaj jest pierwsza linia każdego CMakeLists.txt
, która jest wymaganą nazwą pliku, którego szuka CMake:
cmake_minimum_required(VERSION 3.1)
Wspomnijmy trochę o składni CMake. W nazwie poleceniacmake_minimum_required
nie jest rozróżniana wielkość liter, więc powszechną praktyką jest używanie małych liter. 1 Słowo VERSION
jest specjalnym słowem kluczowym dla tej funkcji. A wartość wersji następuje po słowie kluczowym. Jak wszędzie w tej książce, wystarczy kliknąć na nazwę polecenia, aby zobaczyć oficjalną dokumentację, i użyć rozwijanej listy, aby przełączać dokumentację pomiędzy wersjami CMake.
Ta linia jest specjalna! 2 Wersja CMake będzie również dyktować zasady, które określają zmiany w zachowaniu. Tak więc, jeśli ustawisz minimum_required
na VERSION2.8
, otrzymasz nieprawidłowe zachowanie linkowania na macOS, na przykład, nawet w najnowszych wersjach CMake. Jeśli ustawisz ją na 3.3 lub niższą, otrzymasz nieprawidłowe zachowanie ukrytych symboli, itd. Lista polityk i wersji jest dostępna atpolicies.
Począwszy od CMake 3.12, obsługuje to zakres, taki jak VERSION 3.1...3.15
; oznacza to, że obsługujesz tak niski poziom jak 3.1, ale przetestowałeś go również z ustawieniami newpolicy do 3.15. Jest to znacznie przyjemniejsze dla użytkowników, którzy potrzebują lepszych ustawień, a dzięki sztuczce w składni, jest wstecznie kompatybilne ze starszymi wersjami CMake (chociaż w rzeczywistości uruchomienie CMake 3.1-3.11 ustawi tylko wersję 3.1 polityk w tym przykładzie, ponieważ te wersje nie traktowały tego specjalnie). Nowe wersje polityk są zwykle najważniejsze dla użytkowników systemów macOS i Windows, którzy również zazwyczaj mają bardzo aktualną wersję CMake.
Tak powinny postępować nowe projekty:
cmake_minimum_required(VERSION 3.7...3.20)if(${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})endif()
Jeśli wersja CMake jest mniejsza niż 3.12, blok if będzie miał wartość true, a polityki zostaną ustawione na aktualną wersję CMake. Jeśli CMake jest 3.12 lub wyższy, ifblock będzie false, ale nowa składnia w cmake_minimum_required
będzie respektowana i to będzie nadal działać poprawnie!
Ostrzeżenie: Tryb serwera CMake MSVC pierwotnie miał problem z odczytaniem tego formatu, więc jeśli potrzebujesz obsługiwać kompilacje Windows bez wiersza poleceń dla starszych wersji MSVC, będziesz chciał zrobić to zamiast tego:
cmake_minimum_required(VERSION 3.7)if(${CMAKE_VERSION} VERSION_LESS 3.20) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})else() cmake_policy(VERSION 3.20)endif()
Jeśli naprawdę potrzebujesz ustawić tutaj niską wartość, możesz użyćcmake_policy
do warunkowego zwiększenia poziomu polityki lub ustawić specyficzną politykę. Proszę przynajmniej zrobić to dla użytkowników macOS!
Ustawianie projektu
Teraz każdy plik CMake najwyższego poziomu będzie miał następującą linię:
project(MyProject VERSION 1.0 DESCRIPTION "Very nice project" LANGUAGES CXX)
Teraz widzimy jeszcze więcej składni. Łańcuchy są cytowane, spacja nie ma znaczenia, a nazwa projektu jest pierwszym argumentem (pozycyjnym). Wszystkie słowa kluczowe są opcjonalne. Wersja ustawia kilka zmiennych, takich jakMyProject_VERSION
i PROJECT_VERSION
. Języki to C
, CXX
,Fortran
, ASM
, CUDA
(CMake 3.8+), CSharp
(3.8+), i SWIFT
(CMake3.15+ experimental). C CXX
jest wartością domyślną. W CMake 3.9 dodano DESCRIPTION
, aby ustawić także opis projektu. Dokumentacja dlaproject
może być pomocna.
Można dodawać komentarze za pomocą znaku #
. CMake posiada również składnię inline dla komentarzy, ale jest ona rzadko używana.
Naprawdę nie ma nic specjalnego w nazwie projektu. W tym momencie nie są dodawane żadne cele.
Robienie pliku wykonywalnego
Pomimo że biblioteki są o wiele bardziej interesujące i spędzimy z nimi większość naszego czasu, zacznijmy od prostego pliku wykonywalnego.
add_executable(one two.cpp three.h)
Jest kilka rzeczy do rozpakowania. one
jest zarówno nazwą wygenerowanego pliku wykonywalnego, jak i nazwą utworzonego celu CMake (wkrótce usłyszysz o wiele więcej o celach, obiecuję). Lista plików źródłowych jest następna i możesz ich wypisać tyle, ile chcesz. CMake jest sprytny i będzie kompilował tylko pliki źródłowe z rozszerzeniem. Nagłówki będą, w większości przypadków, ignorowane; jedynym powodem ich wypisania jest chęć wyświetlenia ich w IDE. Cele są wyświetlane jako foldery w wielu IDE. Więcej o ogólnym systemie budowania i celach jest dostępne w buildsystem.
Utworzenie biblioteki
Utworzenie biblioteki jest wykonywane za pomocą add_library
, i jest tak samo proste:
add_library(one STATIC two.cpp three.h)
Możesz wybrać typ biblioteki, STATIC, SHARED, lub MODUŁ. Jeśli pozostawisz ten wybór wyłączony, wartość BUILD_SHARED_LIBS
będzie użyta do wyboru między STATIC i SHARED.
Jak zobaczysz w następnych sekcjach, często będziesz potrzebował zrobić fikcyjny cel, to jest taki, gdzie nic nie musi być skompilowane, na przykład, dla biblioteki tylko nagłówkowej. Nazywa się to biblioteką INTERFACE, i jest kolejnym wyborem; jedyną różnicą jest to, że nie mogą po niej następować nazwy plików.
Możesz także utworzyć ALIAS
bibliotekę z istniejącą biblioteką, co po prostu daje ci nową nazwę dla celu. Jedyną korzyścią z tego jest to, że możesz tworzyć biblioteki z ::
w nazwie (co zobaczysz później). 3
Cele są twoim przyjacielem
Teraz określiliśmy cel, jak dodać informacje o nim? Na przykład, może potrzebuje on katalogu include:
target_include_directories(one PUBLIC include)
target_include_directories
dodaje katalog include do celu. PUBLIC
nie znaczy wiele dla pliku wykonywalnego; dla biblioteki pozwala CMake’owi wiedzieć, że wszystkie cele, które linkują do tego celu, muszą również potrzebować tego katalogu include. Inne opcje to PRIVATE
(wpływają tylko na bieżący cel, nie na zależności) i INTERFACE
(potrzebne tylko dla zależności).
Możemy następnie połączyć cele w łańcuchy:
add_library(another STATIC another.cpp another.h)target_link_libraries(another PUBLIC one)
target_link_libraries
jest prawdopodobnie najbardziej użytecznym i najbardziej zagmatwanym poleceniem w CMake. Pobiera ono cel (another
) i dodaje zależność, jeśli cel jest podany. Jeśli nie istnieje cel o tej nazwie (one
), to dodaje link do biblioteki o nazwie one
na twojej ścieżce (stąd nazwa polecenia). Możesz też podać pełną ścieżkę do biblioteki. Lub flagę linkera. Aby dodać jeszcze trochę zamieszania, klasyczny CMake pozwalał na pominięcie wyboru słowa kluczowego PUBLIC
, itd. Jeśli zostało to zrobione na celu, otrzymasz błąd, jeśli spróbujesz mieszać style w dalszej części łańcucha.
Skup się na używaniu celów wszędzie i słów kluczowych wszędzie, a będzie dobrze.
Cele mogą mieć katalogi include, połączone biblioteki (lub połączone cele), opcje kompilacji, definicje kompilacji, cechy kompilacji (zobacz rozdział C++11) i wiele więcej. Jak zobaczysz w dwóch rozdziałach poświęconych projektom, często można uzyskać cele (i zawsze tworzyć cele), które reprezentują wszystkie biblioteki, których używasz. Nawet rzeczy, które nie są prawdziwymi bibliotekami, jak OpenMP, mogą być reprezentowane przez cele. To dlatego Modern CMake jest świetny!
Zanurz się
Zobacz, czy możesz podążać za poniższym plikiem. Tworzy on prostą bibliotekę C++11 i program z niej korzystający. Nie ma żadnych zależności. Więcej standardowych opcji C++ omówię później, na razie używając systemu CMake 3.8.
cmake_minimum_required(VERSION 3.8)project(Calculator LANGUAGES CXX)add_library(calclib STATIC src/calclib.cpp include/calc/lib.hpp)target_include_directories(calclib PUBLIC include)target_compile_features(calclib PUBLIC cxx_std_11)add_executable(calc apps/calc.cpp)target_link_libraries(calc PUBLIC calclib)
1. W tej książce będę głównie unikał pokazywania Ci złych sposobów robienia rzeczy; możesz znaleźć mnóstwo takich przykładów w sieci. Od czasu do czasu wspomnę o alternatywnych rozwiązaniach, ale nie są one zalecane, chyba że są absolutnie konieczne; często są one tylko po to, aby pomóc ci w czytaniu starszego kodu CMake.
2. Czasami zobaczysz tutaj
FATAL_ERROR
, który był potrzebny do obsługi ładnych awarii podczas uruchamiania tego w CMake <2.6, co nie powinno już być problemem.
3. Składnia
::
była pierwotnie przeznaczona dlaINTERFACE IMPORTED
bibliotek, które wyraźnie miały być bibliotekami zdefiniowanymi poza bieżącym projektem. Jednak z tego powodu większość poleceńtarget_*
nie działa na bibliotekachIMPORTED
, co utrudnia ich samodzielną konfigurację. Dlatego na razie nie używaj słowa kluczowegoIMPORTED
, a zamiast niego użyj celuALIAS
; będzie dobrze, dopóki nie zaczniesz eksportować celów. To ograniczenie zostało naprawione w CMake 3.11.